Parcours
/
Factor
Factor
/
Exercices
/
Voitures, assemble !
Voitures, assemble !

Voitures, assemble !

Exercice d'apprentissage

Introduction

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.

Les mots de comparaison

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

Les vérifications d'intervalle

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 quotations

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)

cond

Quand 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 :

  • Les paires sont essayées dans l'ordre. La première qui correspond l'emporte.
  • Une entrée sans prédicat (une seule quotation) à la fin sert de cas par défaut.
  • Chaque prédicat inspecte l'entrée mais doit laisser la pile de données telle qu'il l'a trouvée : dup ... <test> est l'idiome habituel.
  • Le corps de la paire choisie reçoit la même pile que celle qu'a vue le prédicat ; il commence donc en général par retirer l'entrée avec drop, puis empile le résultat.

Instructions

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.

1. Indique si la chaîne est en marche

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"

2. Calcule le taux de réussite

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

3. Calcule le taux de production par heure

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.

4. Calcule le nombre de pièces fonctionnelles produites par minute

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
Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet
Factor Exercism

Prêt à commencer Voitures, assemble ! ?

Inscris-toi sur Exercism pour apprendre et maîtriser Factor avec 47 concepts163 exercices, et un vrai mentorat humain, le tout gratuitement.