Μερικές φορές ένα κομμάτι κατάστασης πρέπει να μοιράζεται ανάμεσα σε πολλές λέξεις, χωρίς να το περνάς κάθε φορά μέσα από τα stack effects τους. Οι δυναμικές μεταβλητές της Factor, που δηλώνονται με SYMBOL:, δίνουν σε κάθε λέξη πρόσβαση σε μια τιμή που είναι αποθηκευμένη σε έναν χώρο ονομάτων.
SYMBOL: και SYMBOLS:
Το SYMBOL: name δηλώνει μία μεταβλητή. Το SYMBOLS: a b c ; δηλώνει πολλές μαζί:
USING: namespaces ;
SYMBOLS: counter total ;
Τα set-global και get-global (στο namespaces) λειτουργούν στον καθολικό χώρο ονομάτων:
set-global ( value variable -- )
get-global ( variable -- value )
change-global ( variable quot: ( old -- new ) -- )
0 counter set-global
counter get-global . ! => 0
counter [ 10 + ] change-global
counter get-global . ! => 10
Για κατάσταση σε επίπεδο module, οι εκδοχές -global είναι αυτές που χρειάζεσαι.
with-variable
Μια δυναμική μεταβλητή υποστηρίζει επίσης μια δεύτερη εκδοχή, με εμβέλεια. Τα set / get / change (χωρίς την κατάληξη -global) διαβάζουν και γράφουν την τρέχουσα δυναμική εμβέλεια, και το with-variable (στο namespaces) δημιουργεί μια νέα εμβέλεια όσο διαρκεί μια παράθεση:
with-variable ( value variable quot -- )
set ( value variable -- )
get ( variable -- value )
change ( variable quot: ( old -- new ) -- )
Η μεταβλητή είναι δεσμευμένη στην value όσο εκτελείται η quot; μόλις αυτή επιστρέψει, η δέσμευση εξαφανίζεται. Αυτό επιτρέπει σε έναν εξωτερικό καλούντα να "εισάγει" μια τιμή που ο εσωτερικός κώδικας μπορεί να διαβάσει, χωρίς να την περνά μέσα από κάθε stack signature.
SYMBOL: greeting
"Hello" greeting [
greeting get . ! => "Hello"
"Howdy" greeting set
greeting get . ! => "Howdy"
greeting [ "!" append ] change
greeting get . ! => "Howdy!"
] with-variable
greeting get-global . ! => f (the scoped binding is gone)
Αυτή η άσκηση χρησιμοποιεί την καθολική εκδοχή σε όλη τη διάρκεια, αλλά το να αναγνωρίζεις την παράλληλη οικογένεια set/get/change είναι χρήσιμο όταν διαβάζεις κώδικα άλλων.
Επειδή οι δυναμικές μεταβλητές κρατούν μια αναφορά, μπορείς να κρατάς μια μεταβλητή συλλογή μέσα σε μία από αυτές και να την ενημερώνεις επιτόπου:
SYMBOL: history
V{ } clone history set-global
"first event" history get-global push
"second event" history get-global push
history get-global .
! => V{ "first event" "second event" }
Το V{ … } είναι ένα literal διάνυσμα. Πάντα να κάνεις clone σε ένα literal V{ } πριν το αποθηκεύσεις: τα literals μοιράζονται μεταξύ των κλήσεων.
find, το πρώτο ταίριασμαΤο find (στο sequences) επιστρέφει το πρώτο στοιχείο για το οποίο ένα κατηγόρημα είναι αληθές, μαζί με τη θέση του:
find ( seq quot -- index elt/f )
Αν δεν ταιριάζει τίποτα, και οι δύο τιμές είναι f. Το να πετάξεις τη θέση με το nip και να χρησιμοποιήσεις το unless* είναι ο καθιερωμένος συνδυασμός για "προεπιλογή αν λείπει".
reject, πέταξε τα ταιριάσματαΤο reject (επίσης στο sequences) είναι το αντίθετο του filter: επιστρέφει τα στοιχεία που αποτυγχάνουν στο κατηγόρημα.
Ο σύλλογος της γειτονιάς σου σου ζητά να διαχειριστείς τις εγγραφές στα παρτέρια του κήπου. Η κατάσταση αποθηκεύεται σε δύο δυναμικές μεταβλητές:
registrations — ένα διάνυσμα από πλειάδες plot που είναι αυτή τη στιγμή ανατεθειμένες σε κάποιο άτομο.next-id — ο ακέραιος που θα χρησιμοποιηθεί για την επόμενη εγγραφή.Η πλειάδα plot έχει δύο θέσεις:
| θέση | τύπος |
|---|---|
id |
ακέραιος |
registered-to |
συμβολοσειρά |
Όρισε τη συνάρτηση open-garden ώστε να αρχικοποιεί τις δυναμικές μεταβλητές: ένα κενό διάνυσμα για το registrations και 1 για το next-id. Στη συνέχεια, όρισε τη συνάρτηση list-registrations ώστε να επιστρέφει το τρέχον διάνυσμα με τις πλειάδες plot.
open-garden
list-registrations .
! => V{ }
Όρισε τη συνάρτηση register ώστε να παίρνει ένα όνομα από τη στοίβα, να δημιουργεί μια νέα πλειάδα plot με το επόμενο διαθέσιμο id, να την προσθέτει στο διάνυσμα registrations, να αυξάνει το next-id κατά ένα και να επιστρέφει τη νέα πλειάδα plot.
open-garden
"Emma Balan" register .
! => T{ plot { id 1 } { registered-to "Emma Balan" } }
list-registrations .
! => V{ T{ plot { id 1 } { registered-to "Emma Balan" } } }
Τα id των παρτεριών πρέπει να είναι μοναδικά και να αυξάνονται ακόμη και μετά από μια ελευθέρωση. Το next-id δεν πρέπει ποτέ να ξαναχρησιμοποιεί μια τιμή.
Όρισε τη συνάρτηση release ώστε να παίρνει ένα id και να αφαιρεί την αντίστοιχη καταχώριση από το registrations. Η ελευθέρωση ενός άγνωστου id δεν κάνει τίποτα.
open-garden
"Emma" register drop
1 release
list-registrations .
! => V{ }
Όρισε τη συνάρτηση get-registration ώστε να παίρνει ένα id και να επιστρέφει την αντίστοιχη πλειάδα plot ή το σύμβολο not-found αν κανένα παρτέρι δεν έχει αυτό το id.
open-garden
"Emma" register drop
1 get-registration .
! => T{ plot { id 1 } { registered-to "Emma" } }
7 get-registration .
! => not-found
Όρισε τη συνάρτηση find-by-name ώστε να παίρνει ένα όνομα και να επιστρέφει ένα διάνυσμα με όλες τις πλειάδες plot που είναι αυτή τη στιγμή καταχωρισμένες σε αυτό το άτομο.
open-garden
"Emma" register drop
"Bob" register drop
"Emma" register drop
"Emma" find-by-name .
! => V{ T{ plot { id 1 } { registered-to "Emma" } }
T{ plot { id 3 } { registered-to "Emma" } } }
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Factor με 47 έννοιες163 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.