Διαδρομές
/
Factor
Factor
/
Ασκήσεις
/
Ο φωστήρας των λαζανιών
Ο φωστήρας των λαζανιών

Ο φωστήρας των λαζανιών

Άσκηση εκμάθησης

Εισαγωγή

Το παιχνίδι με τη στοίβα είναι μια χαρά για σύντομες λέξεις. Όταν μια λέξη έχει πολλαπλές εισόδους και χρειάζεται να τις αναφέρεις με το όνομά τους, ο Factor προσφέρει τις τοπικές μεταβλητές, δεσμεύσεις με όνομα που εισάγονται με :: (για ορισμούς λέξεων) ή [| | ] (για ενσωματωμένες λάμδα).

:: ( inputs -- outputs )

Αντικατέστησε το : με :: και τα ονόματα των εισόδων γίνονται τοπικές μεταβλητές στο σώμα:

USING: locals ;

:: hypotenuse ( a b -- c )
    a a *
    b b *
    + sqrt ;

Σύγκρινε με την έκδοση που ανακατεύει τη στοίβα:

! DOCTEST: SKIP   (shown for comparison — would re-define hypotenuse)
: hypotenuse ( a b -- c )
    [ sq ] bi@ + sqrt ;

Και οι δύο είναι έγκυρες, αλλά οι τοπικές μεταβλητές λάμπουν όταν μια είσοδος χρησιμοποιείται πάνω από μία φορά ή όταν η σειρά των πράξεων δεν ευθυγραμμίζεται φυσικά με τη σειρά της στοίβας.

Δέσμευση ενδιάμεσων τιμών με :>

Μέσα σε ένα σώμα :: (ή σε μια ενσωματωμένη λάμδα [| ... |]), το :> βγάζει μια τιμή από τη στοίβα δεδομένων και τη δεσμεύει σε μια νέα τοπική μεταβλητή:

value :> name      ! immutable binding
value :> name!     ! mutable binding (name! is its setter)

Η αμετάβλητη μορφή είναι η συνηθισμένη. Χρησιμοποίησέ την για να ονομάσεις ένα ενδιάμεσο αποτέλεσμα, ώστε το σώμα να διαβάζεται από πάνω προς τα κάτω:

USING: locals math ;

:: average-3 ( x y z -- avg )
    x y + z + :> sum
    sum 3 / ;

Η παραλλαγή με ! δηλώνει ότι η τοπική μεταβλητή μπορεί να τροποποιηθεί· αργότερα στο σώμα, το value name! (χωρίς άνω και κάτω τελεία, χωρίς :>) της αναθέτει νέα τιμή:

USING: kernel locals math math.order ;

:: clamped ( x lo hi -- y )
    x :> v!
    v lo < [ lo v! ] when
    v hi > [ hi v! ] when
    v ;

Οι τοπικές μεταβλητές που μπορούν να τροποποιηθούν λάμπουν μέσα στις λέξεις επανάληψης που θα συναντήσεις σε επόμενες ασκήσεις (π.χ. while).

[let: μια εμβέλεια από οπουδήποτε

Το :> λειτουργεί μόνο μέσα σε μια λεκτική εμβέλεια, την οποία δημιουργούν αυτόματα τα :: και [| ... |]. Για να εισάγεις τοπικές μεταβλητές από μια απλή λέξη : ή από το listener, τύλιξε τον κώδικα σε [let ... ]:

[let code :> name code :> name ... body ]

Κάθε :> name δεσμεύει την τιμή που βρίσκεται στην κορυφή της στοίβας από την προηγούμενη έκφραση· οι δεσμεύσεις είναι ορατές στο υπόλοιπο της φόρμας.

USING: locals math ;

[let 3 :> x 4 :> y x x * y y * + ] .   ! => 25

Το [let είναι η γέφυρα ανάμεσα στους ορισμούς : στυλ στοίβας και τις δεσμεύσεις με όνομα, και είναι βολικό όταν μόνο ένα κομμάτι μιας λέξης ωφελείται από τις τοπικές μεταβλητές.

Λάμδα: [| inputs | body ]

Μέσα σε μια παράθεση, το [| inputs | body ] εισάγει τοπικές μεταβλητές στις οποίες το σώμα μπορεί να αναφέρεται με το όνομά τους. Αυτό είναι ιδιαίτερα χρήσιμο με λέξεις υψηλότερης τάξης όπως το assoc-map, του οποίου η παράθεση δέχεται το key και το value:

USING: assocs locals ;

H{ { "a" 1 } { "b" 2 } }
[| key value | key value neg ] assoc-map .
! => H{ { "a" -1 } { "b" -2 } }

Το ίδιο σχήμα λειτουργεί και για το map-index (στη βιβλιοθήκη [sequences][sequences]), του οποίου η παράθεση δέχεται το στοιχείο και τη θέση του. Τα ονόματα κάνουν σαφές ποιος τελεστέος παίζει ποιον ρόλο:

USING: locals sequences ;

! Divide each element by its 1-based position:
{ 10 80 270 } [| elt i | elt i 1 + / ] map-index .
! => { 10 40 90 }

Η επίδραση στη στοίβα της λάμδα καθορίζεται από τη λίστα εισόδων και από αυτά που παράγει το σώμα της.

Πότε να χρησιμοποιείς τοπικές μεταβλητές

Κατέφυγε στις τοπικές μεταβλητές όταν:

  • Η ίδια είσοδος χρησιμοποιείται σε περισσότερα από ένα σημεία.
  • Η φυσική σειρά των πράξεων δεν ταιριάζει με τη σειρά της στοίβας, και τα dup/swap/rot που θα το διορθώσουν είναι δυσανάγνωστα.
  • Βρίσκεσαι μέσα σε μια ενσωματωμένη λάμδα που περνιέται σε μια λέξη υψηλότερης τάξης, η οποία σου δίνει πολλές τιμές ταυτόχρονα (όπως στο assoc-map).

Όταν το σώμα είναι μια καθαρή γραμμική ροή, οι απλοί ορισμοί : παραμένουν πιο σύντομοι και τουλάχιστον εξίσου ευανάγνωστοι.

assoc-map: μία καταχώριση τη φορά

Το assoc-map (στη βιβλιοθήκη assocs) αντιστοιχίζει μια παράθεση σε κάθε καταχώριση μιας συσχετιστικής συλλογής:

assoc-map ( assoc quot: ( key value -- newkey newvalue ) -- newassoc )

Μια λάμδα με τοπικές μεταβλητές είναι ο πιο καθαρός τρόπος να γράψεις την παράθεση.

Επιστροφή στο cond

Όταν πρέπει να αποφασίσεις με βάση το f ή μια αριθμητική τιμή, το cond έχει ακριβώς το σωστό σχήμα, και δεν χρειάζεται case, επειδή δεν υπάρχει μία και μοναδική τιμή για σύγκριση.

Οδηγίες

Είσαι πάλι στην κουζίνα και βελτιώνεις τη συνταγή για λαζάνια από το Leah's Luscious Lasagna. Οι εργασίες εδώ σου ζητούν να χειριστείς πολλές εισόδους ταυτόχρονα, και τότε ακριβώς είναι που τα locals, οι ονομασμένες δεσμεύσεις της Factor, δικαιώνουν την ύπαρξή τους.

1. Προσδιόρισε την κατάσταση μαγειρέματος

Όρισε τη cooking-status ώστε να παίρνει μια ένδειξη του χρονοδιακόπτη από τη στοίβα και να επιστρέφει μια συμβολοσειρά κατάστασης.

  • 0 → "Lasagna is done."
  • f (ο χρονοδιακόπτης δεν είχε οριστεί ποτέ) → "You forgot to set the timer."
  • οποιοσδήποτε άλλος αριθμός → "Not done, please wait."
12 cooking-status .   ! => "Not done, please wait."
0 cooking-status .    ! => "Lasagna is done."
f cooking-status .    ! => "You forgot to set the timer."

2. Υπολόγισε κατά προσέγγιση τον χρόνο προετοιμασίας

Όρισε τη preparation-time ώστε να παίρνει έναν πίνακα με ονόματα στρώσεων και έναν μέσο αριθμό λεπτών ανά στρώση, και να επιστρέφει τον συνολικό χρόνο προετοιμασίας.

{ "sauce" "noodles" "sauce" "meat" "mozzarella" "noodles" } 3 preparation-time .
! => 18

3. Υπολόγισε τα ζυμαρικά και τη σάλτσα που χρειάζεσαι

Όρισε τη quantities ώστε να παίρνει έναν πίνακα με ονόματα στρώσεων και να επιστρέφει δύο τιμές: τα γραμμάρια ζυμαρικών που χρειάζονται (50 g ανά στρώση ζυμαρικών) και τα λίτρα σάλτσας που χρειάζονται (1/5 λίτρου ανά στρώση σάλτσας).

{ "sauce" "noodles" "sauce" "meat" "mozzarella" "noodles" } quantities .s
! => 100
! => 2/5

4. Πρόσθεσε το μυστικό συστατικό

Ο φίλος σου στέλνει μια λίστα με συστατικά· το τελευταίο στοιχείο είναι το μυστικό του. Όρισε τη add-secret-ingredient ώστε να παίρνει τη δική του λίστα και τη δική σου και να επιστρέφει τη λίστα σου με το μυστικό στο τέλος.

{ "noodles" "sauce" "mozzarella" "kampot pepper" }
{ "noodles" "meat" "sauce" "mozzarella" }
add-secret-ingredient .
! => { "noodles" "meat" "sauce" "mozzarella" "kampot pepper" }

5. Κλιμάκωσε τη συνταγή

Η συνταγή του βιβλίου μαγειρικής βγάζει δύο μερίδες. Όρισε τη scale-recipe ώστε να παίρνει μια συνταγή (έναν hashtable από όνομα συστατικού σε ποσότητα) και έναν αριθμό μερίδων-στόχο, και να επιστρέφει μια νέα συνταγή κλιμακωμένη ανάλογα.

H{ { "noodles" 200 } { "sauce" 1/2 } { "mozzarella" 1 } { "meat" 100 } }
4 scale-recipe .
! => H{ { "noodles" 400 } { "sauce" 1 } { "mozzarella" 2 } { "meat" 200 } }
Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα
Factor Exercism

Έτοιμος να ξεκινήσεις την άσκηση Ο φωστήρας των λαζανιών;

Γράψου στο Exercism για να μάθεις και να κατακτήσεις Factor με 47 έννοιες163 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.