Όταν χρειάζεσαι μια σειρά από n τιμές, όπου η καθεμία εξαρτάται από τη θέση της, το <iota> και το map της Factor συνεργάζονται για να κάνουν τη δουλειά χωρίς να γράψεις μετρητή βρόχου.
<iota> και map
Το <iota> (στο sequences) παίρνει έναν μη αρνητικό ακέραιο n και επιστρέφει μια εικονική ακολουθία από τους ακεραίους 0, 1, …, n-1. Στη συνέχεια, το map τη διατρέχει, εφαρμόζοντας το quotation σου σε κάθε στοιχείο:
USING: math sequences ;
5 <iota> [ 2 * ] map . ! => { 0 2 4 6 8 }
Το quotation δέχεται έναν ακέραιο, τη θέση, και αφήνει την τιμή για αυτή τη θέση στη στοίβα.
Όταν χρειάζεσαι μόνο τις παρενέργειες της επίσκεψης κάθε θέσης και όχι μια νέα ακολουθία, το each-integer (στο math) τρέχει ένα quotation πάνω στο 0, 1, …, n-1:
each-integer ( n quot: ( i -- ) -- )
Το replicate (στο sequences) καλεί ένα quotation n φορές και συλλέγει τα αποτελέσματα, αγνοώντας τη θέση. Είναι βολικό για να φτιάξεις n ανεξάρτητες τιμές:
replicate ( n quot: ( -- elt ) -- seq )
USING: sequences ;
3 [ { 0 0 } ] replicate . ! => { { 0 0 } { 0 0 } { 0 0 } }
Όταν το διάστημα των θέσεων δεν ξεκινά από το 0 ή θέλεις να περιλαμβάνει και τα δύο άκρα, το λεξιλόγιο ranges παρέχει literals με τη σημειογραφία των διαστημάτων. Οι τετράγωνες αγκύλες περιλαμβάνουν το άκρο, ενώ οι στρογγυλές παρενθέσεις το αποκλείουν.
[a..b] ! a, a+1, …, b (inclusive)
[a..b) ! a, a+1, …, b-1 (half-open at the top)
USING: math ranges sequences ;
3 7 [a..b] [ 2 * ] map . ! => { 6 8 10 12 14 }
3 7 [a..b) [ 2 * ] map . ! => { 6 8 10 12 }
Μερικές συνηθισμένες συντομεύσεις με ένα όρισμα:
[1..b] ! 1, 2, …, b (same as 1 b [a..b])
[1..b) ! 1, 2, …, b-1 (same as 1 b [a..b))
[0..b) ! 0, 1, …, b-1 (same as 0 b [a..b), and same as `b <iota>`)
6 [1..b] [ sq ] map . ! => { 1 4 9 16 25 36 }
6 [1..b) [ sq ] map . ! => { 1 4 9 16 25 }
4 [0..b) [ 1 + ] map . ! => { 1 2 3 4 }
Το <iota> είναι η πιο συνηθισμένη μορφή. Το [a..b] και τα συναφή είναι το σωστό εργαλείο όταν το διάστημα ξεκινά από κάπου αλλού εκτός από το 0 ή χρειάζεται να περιλαμβάνει και το πάνω άκρο.
Οι τετράγωνες αγκύλες περιλαμβάνουν ένα άκρο, ενώ οι παρενθέσεις το αποκλείουν. Το ίδιο τρικ στην αριστερή πλευρά δίνει (a..b] και (a..b):
(a..b] ! a+1, …, b (lower open, upper inclusive)
(a..b) ! a+1, …, b-1 (both open)
Το 0 n (a..b] δίνει { 1 … n } για n > 0 και { } για n = 0, τη φυσική μορφή όταν επαναλαμβάνεις για "κάθε θετικό ακέραιο μέχρι και το n".
Και οι τέσσερις μορφές, τα [a..b], [a..b), (a..b], (a..b), μετρούν αντίστροφα όταν a > b, και όχι προς ένα κενό αποτέλεσμα:
USING: ranges sequences ;
5 1 [a..b] >array . ! => { 5 4 3 2 1 }
1 0 [a..b] >array . ! => { 1 0 } (not empty!)
Το map παράγει όποια μορφή επιστρέφει το quotation του. Αν το quotation αφήσει έναν κωδικό χαρακτήρα στη στοίβα, το >string (στο strings) μετατρέπει το αποτέλεσμα σε συμβολοσειρά:
USING: math sequences strings ;
4 <iota> [ 2 * CHAR: A + ] map >string . ! => "ACEG"
Το CHAR: A μεταφράζεται στον ακέραιο 65. Το quotation εδώ διπλασιάζει τη θέση και προσθέτει αυτή τη βάση, καταλήγοντας σε κάθε δεύτερο κεφαλαίο γράμμα. Όποια αριθμητική προσθέσεις πάνω στη θέση καθορίζει ποιος χαρακτήρας θα καταλήξει σε αυτή τη θέση.
Όταν ο χαρακτήρας εξαρτάται από μια συνθήκη που αφορά τη θέση, κάνε την επιλογή μέσα στο quotation:
USING: kernel math sequences strings ;
5 <iota> [ 3 < [ CHAR: a ] [ CHAR: b ] if ] map >string .
! => "aaabb"
Οι τρεις πρώτες θέσεις δίνουν t στο τεστ i 3 <, οπότε παίρνουν a, ενώ οι υπόλοιπες παίρνουν b. Η ίδια μορφή, [ <test> [ <yes> ] [ <no> ] if ], καλύπτει τους ελέγχους άρτιου/περιττού με τα even? / odd? (στο math) και τους ελέγχους "κάθε k-οστή θέση" με τα mod και zero?.
Ένα ρομπότ πάρτι κρεμάει γιρλάντες για τη μεγάλη γιορτή. Κάθε σειρά γιρλάντας είναι μια οριζόντια σειρά από n μικρές σημαιούλες, και ο χαρακτήρας κάθε σημαιούλας καθορίζεται από τη θέση της στη σειρά, μετρώντας από αριστερά ξεκινώντας από το 0. Βοήθησε το ρομπότ να συναρμολογήσει τα παρακάτω μοτίβα.
Όρισε την alphabet-bunting ώστε να παίρνει έναν μη αρνητικό ακέραιο n από τη στοίβα και να επιστρέφει μια συμβολοσειρά με τα πρώτα n πεζά γράμματα του αλφαβήτου.
5 alphabet-bunting .
! => "abcde"
0 alphabet-bunting .
! => ""
Μπορείς να υποθέσεις ότι το n είναι το πολύ 26.
Όρισε την counting-bunting ώστε να παίρνει το n και να επιστρέφει μια συμβολοσειρά από n ψηφία, όπου η σημαιούλα στη θέση i δείχνει το i mod 10.
12 counting-bunting .
! => "012345678901"
Όρισε τη stripe-bunting ώστε να εναλλάσσει δύο χαρακτήρες: οι ζυγές θέσεις παίρνουν * και οι μονές θέσεις παίρνουν -.
6 stripe-bunting .
! => "*-*-*-"
1 stripe-bunting .
! => "*"
Κάθε πέμπτη σημαιούλα είναι ένα ειδικό σημάδι. Όρισε τη marker-bunting ώστε οι θέσεις 0, 5, 10, … να παίρνουν | και οι υπόλοιπες να παίρνουν ..
11 marker-bunting .
! => "|....|....|"
Το ρομπότ κρεμάει μια γιρλάντα σταθερού μεγέθους με 10 σημαιούλες που στερεώνεται σε έναν γάντζο στο κέντρο. Μετρώντας από την αριστερότερη σημαιούλα στη θέση -5 μέχρι (αλλά χωρίς να συμπεριλαμβάνεται) το 5, ο χαρακτήρας κάθε σημαιούλας είναι η απόσταση από το κέντρο, γραμμένη ως ψηφίο.
Όρισε τη valley-bunting (χωρίς ορίσματα) ώστε να επιστρέφει αυτή τη σταθερή συμβολοσειρά.
valley-bunting .
! => "5432101234"
Γράψου στο Exercism για να μάθεις και να κατακτήσεις Factor με 47 έννοιες163 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.