Cet exercice introduit les structures conditionnelles, c'est-à-dire le choix entre deux lignes de conduite ou plus selon une valeur. Il s'appuie sur les booléens que tu as rencontrés dans Infiltration d'Annalyn et sur l'arithmétique des entiers de Conversion de devises.
Tous ces mots se trouvent dans math (et dans kernel pour =) :
= ( x y -- ? ) ! equal
< ( x y -- ? ) ! less than
<= ( x y -- ? ) ! less than or equal
> ( x y -- ? ) ! greater than
>= ( x y -- ? ) ! greater than or equal
3 3 = . ! => t
2 3 < . ! => t
3 3 <= . ! => t
3 4 = not . ! => t (inequality: combine = with not)
zero? (dans math) est un raccourci pour le test courant 0 = : il consomme le nombre et empile un booléen indiquant s'il valait zéro :
zero? ( n -- ? ) ! t when n is 0
between? (dans math.order) teste si une valeur tombe dans un intervalle inclusif. C'est pratique quand une action dépend de la tranche dans laquelle un nombre tombe :
between? ( x lo hi -- ? ) ! lo <= x <= hi (inclusive)
5 1 10 between? . ! => t
0 1 10 between? . ! => f
10 1 10 between? . ! => t (inclusive at both ends)
Tu le verras souvent employé comme prédicat de cond (dup 1 4 between?) pour choisir une branche selon un intervalle plutôt que selon une valeur unique.
Les mots de comparaison ci-dessus produisent des booléens ; pour agir sur un booléen, tu passes une ou plusieurs quotations à la structure conditionnelle. Une quotation est un fragment de code entouré de crochets, [ ... ]. Le simple fait de l'écrire empile ce code sur la pile en tant que valeur au lieu de l'exécuter : un mot comme if décide ensuite quelle quotation exécuter.
[ neg ] ! a quotation that negates the top of the stack
[ ] ! the empty quotation — does nothing
Un exercice ultérieur traite des quotations en détail ; pour l'instant, lis [ ... ] comme « le code à exécuter pour cette branche ».
if, when et unless
if (dans kernel) prend un booléen et deux quotations. Il exécute la première quotation quand le booléen est vrai, et la seconde quand il est faux :
if ( ? then-quot else-quot -- )
: abs ( x -- y ) dup 0 < [ neg ] [ ] if ;
when n'exécute sa quotation que lorsque le booléen est vrai ; unless seulement lorsqu'il est faux :
when ( ? quot -- )
unless ( ? quot -- )
if*, when* et unless*
Trois variantes de kernel traitent le booléen comme une valeur qu'il vaut la peine de conserver lorsqu'il est vrai. C'est utile quand un mot renvoie « la chose, ou f » :
if* ( ? true false -- ) ! truthy: true is called WITH ? on stack
when* ( ? true -- ) ! truthy: true is called WITH ? on stack
unless* ( ? false -- ) ! falsy: false runs and pushes a default
if* est la forme à deux branches. La branche du vrai est appelée avec la valeur encore sur la pile ; celle du faux est appelée sans elle :
42 [ ] [ "nothing" ] if* . ! prints 42
f [ ] [ "nothing" ] if* . ! prints "nothing"
unless* est l'idiome classique de « la valeur ou la valeur par défaut ». Si la valeur est vraie, elle est laissée telle quelle ; si c'est f, la valeur est retirée et la quotation s'exécute pour empiler une valeur de remplacement :
"hello" [ "anonymous" ] unless* . ! => "hello"
f [ "anonymous" ] unless* . ! => "anonymous"
when* est la forme à une branche de if* : il exécute sa quotation, avec la valeur encore sur la pile, uniquement lorsque la valeur est vraie, et se contente de retirer la valeur quand c'est f. Utilise-le pour intégrer un résultat « la chose, ou f » à une valeur en cours de calcul sans avoir à traiter le cas f :
0 41 [ + ] when* . ! => 41 (truthy: 41 added to the running total)
0 f [ + ] when* . ! => 0 (falsy: f dropped, total left untouched)
condQuand tu as plusieurs actions alternatives entre lesquelles choisir, cond (dans combinators) est tout indiqué. Il prend un tableau de paires { predicate body } et exécute le corps du premier prédicat qui produit une valeur vraie :
USING: combinators ;
: classify ( n -- label )
{
{ [ dup 0 < ] [ drop "negative" ] }
{ [ dup 0 = ] [ drop "zero" ] }
[ drop "positive" ]
} cond ;
Quelques détails à noter :
dup ... <test> est l'idiome habituel.drop, puis empile le résultat.Dans cet exercice, tu vas écrire du code pour analyser la production
d'une chaîne de montage dans une usine de voitures. La vitesse de la chaîne
de montage peut aller de 0 (à l'arrêt) à 10 (maximum).
À sa vitesse non nulle la plus basse (1), 221 voitures sont produites
chaque heure. La production augmente linéairement avec la vitesse, donc à la
vitesse 4, la chaîne produit 4 * 221 = 884 voitures par heure. Cependant,
des vitesses plus élevées augmentent la probabilité que des voitures
défectueuses soient produites, lesquelles doivent alors être mises au rebut.
Tu as quatre tâches. Chacune prend un seul paramètre entier, la vitesse de la chaîne de montage, depuis la pile.
Définis production-status pour renvoyer "stopped" quand la vitesse vaut 0
et "running" pour toute autre vitesse :
0 production-status .
! => "stopped"
3 production-status .
! => "running"
Définis success-rate pour renvoyer la probabilité qu'une pièce soit
produite sans erreur :
0: 0.0
1 to 4: 1.0
5 to 8: 0.9
9: 0.8
10: 0.77
10 success-rate .
! => 0.77
Définis production-rate-per-hour pour renvoyer le taux de production
horaire de la chaîne de montage, en tenant compte du taux de réussite.
Tu devras d'abord définir base-speed, la constante 221.
6 production-rate-per-hour .
! => 1193.4
La valeur renvoyée est un nombre à virgule flottante.
Définis working-items-per-minute pour renvoyer combien de voitures
fonctionnelles sont produites par minute. Le résultat est un entier : les
voitures incomplètes ne sont pas comptées.
6 working-items-per-minute .
! => 19
Inscris-toi sur Exercism pour apprendre et maîtriser Factor avec 47 concepts163 exercices, et un vrai mentorat humain, le tout gratuitement.