Quand tu as besoin d'une suite de n valeurs dont chacune dépend de sa position, <iota> et map de Factor coopèrent pour faire le travail sans écrire de compteur de boucle.
<iota> et map
<iota> (dans sequences) prend un entier positif ou nul n et renvoie une séquence virtuelle des entiers 0, 1, …, n-1. map la parcourt ensuite, en appliquant ta quotation à chaque élément :
USING: math sequences ;
5 <iota> [ 2 * ] map . ! => { 0 2 4 6 8 }
La quotation reçoit un entier, l'indice, et laisse sur la pile la valeur de cette position.
Quand tu as seulement besoin des effets de bord de la visite de chaque indice, et non d'une nouvelle séquence, each-integer (dans math) exécute une quotation sur 0, 1, …, n-1 :
each-integer ( n quot: ( i -- ) -- )
replicate (dans sequences) appelle une quotation n fois et rassemble les résultats, en ignorant l'indice, ce qui est pratique pour construire n valeurs indépendantes :
replicate ( n quot: ( -- elt ) -- seq )
USING: sequences ;
3 [ { 0 0 } ] replicate . ! => { { 0 0 } { 0 0 } { 0 0 } }
Quand l'intervalle d'indices ne commence pas à 0, ou que tu le veux inclusif aux deux extrémités, le vocabulaire ranges fournit des littéraux en notation de crochets. Les crochets incluent l'extrémité ; les parenthèses l'excluent.
[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 }
Quelques raccourcis courants à un seul argument :
[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> est la forme la plus courante ; [a..b] et ses variantes sont l'outil approprié quand l'intervalle commence ailleurs qu'à 0 ou qu'il a besoin d'une borne supérieure inclusive.
Les crochets incluent une extrémité ; les parenthèses l'excluent. Le même procédé à gauche donne (a..b] et (a..b) :
(a..b] ! a+1, …, b (lower open, upper inclusive)
(a..b) ! a+1, …, b-1 (both open)
0 n (a..b] donne { 1 … n } pour n > 0 et { } pour n = 0, la forme naturelle quand on itère sur « tous les entiers positifs jusqu'à n inclus ».
Les quatre formes entre crochets, [a..b], [a..b), (a..b] et (a..b), comptent en décroissant quand a > b, au lieu de tendre vers un résultat vide :
USING: ranges sequences ;
5 1 [a..b] >array . ! => { 5 4 3 2 1 }
1 0 [a..b] >array . ! => { 1 0 } (not empty!)
map produit la forme que renvoie sa quotation. Si la quotation laisse un code de caractère sur la pile, >string (dans strings) transforme le résultat en string :
USING: math sequences strings ;
4 <iota> [ 2 * CHAR: A + ] map >string . ! => "ACEG"
CHAR: A s'analyse en l'entier 65. La quotation ici double l'indice et ajoute cette base, ce qui tombe sur une lettre majuscule sur deux. Toute arithmétique que tu empiles par-dessus l'indice décide du caractère qui finit à cette position.
Quand le caractère dépend d'une condition portant sur l'indice, fais le choix à l'intérieur de la quotation :
USING: kernel math sequences strings ;
5 <iota> [ 3 < [ CHAR: a ] [ CHAR: b ] if ] map >string .
! => "aaabb"
Les trois premières positions évaluent i 3 < à t, elles obtiennent donc a ; les autres obtiennent b. La même structure, [ <test> [ <yes> ] [ <no> ] if ], couvre les tests de parité avec even? / odd? (dans math) et les tests « toutes les k-ièmes positions » avec mod et zero?.
Un robot de fête installe des guirlandes de drapeaux pour la grande kermesse. Chaque ligne de guirlande est une rangée horizontale de n petits drapeaux, et le caractère de chaque drapeau dépend de sa position dans la rangée, comptée depuis la gauche en partant de 0. Aide le robot à assembler les motifs ci-dessous.
Définis alphabet-bunting pour qu’elle retire de la pile un entier positif ou nul n et renvoie une string composée des n premières lettres minuscules de l’alphabet.
5 alphabet-bunting .
! => "abcde"
0 alphabet-bunting .
! => ""
Tu peux supposer que n vaut au plus 26.
Définis counting-bunting pour qu’elle prenne n et renvoie une string composée de n chiffres, où le drapeau à la position i affiche i mod 10.
12 counting-bunting .
! => "012345678901"
Définis stripe-bunting pour qu’elle alterne entre deux caractères : les positions paires reçoivent * et les positions impaires reçoivent -.
6 stripe-bunting .
! => "*-*-*-"
1 stripe-bunting .
! => "*"
Un drapeau sur cinq est un marqueur spécial. Définis marker-bunting pour que les positions 0, 5, 10, … reçoivent | et que les autres reçoivent ..
11 marker-bunting .
! => "|....|....|"
Le robot accroche une guirlande de taille fixe, composée de 10 drapeaux, qui s’accroche à un crochet au centre. En comptant depuis le drapeau le plus à gauche, à la position -5, jusqu’à 5 (non compris), le caractère de chaque drapeau est la distance au centre, écrite sous forme de chiffre.
Définis valley-bunting (sans entrée) pour qu’elle renvoie cette string fixe.
valley-bunting .
! => "5432101234"
Inscris-toi sur Exercism pour apprendre et maîtriser Factor avec 47 concepts163 exercices, et un vrai mentorat humain, le tout gratuitement.