Questo esercizio introduce i condizionali, cioè la scelta tra due o più possibili linee d'azione in base a un valore. Si basa sui valori booleani che hai incontrato in L'infiltrazione di Annalyn e sull'aritmetica dei numeri interi di Conversione di valuta.
Si trovano tutte in math (e in kernel per =):
= ( 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? (in math) è una scorciatoia per il test più comune, 0 =: consuma il numero e impila sullo stack un valore che indica se era zero:
zero? ( n -- ? ) ! t when n is 0
between? (in math.order) verifica se un valore cade all'interno di un intervallo inclusivo. È comodo quando un'azione dipende dalla fascia in cui finisce un numero:
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)
Lo vedrai spesso usato come predicato di cond (dup 1 4 between?) per scegliere un ramo in base all'intervallo invece che a un singolo valore.
Le parole di confronto qui sopra producono valori booleani; per agire su un valore booleano passi al condizionale una o più quotation. Una quotation è un frammento di codice racchiuso tra parentesi quadre, [ ... ]. Scriverla impila il codice sullo stack come valore invece di eseguirlo: una parola come if decide poi quale quotation eseguire.
[ neg ] ! a quotation that negates the top of the stack
[ ] ! the empty quotation — does nothing
Un esercizio successivo tratta le quotation in modo completo; per ora, leggi [ ... ] come «il codice da eseguire per questo ramo».
if, when, unless
if (in kernel) prende un valore booleano e due quotation. Esegue la prima quotation quando il booleano è veritiero e la seconda quando è falso:
if ( ? then-quot else-quot -- )
: abs ( x -- y ) dup 0 < [ neg ] [ ] if ;
when esegue la sua quotation solo quando il booleano è veritiero; unless solo quando è falso:
when ( ? quot -- )
unless ( ? quot -- )
if*, when*, e unless*
Tre varianti di kernel trattano il booleano come un valore che vale la pena conservare quando è veritiero. Sono utili quando una parola restituisce «la cosa, oppure 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* è la forma a due rami. Il ramo veritiero viene chiamato con il valore ancora sullo stack; il ramo falso viene chiamato senza:
42 [ ] [ "nothing" ] if* . ! prints 42
f [ ] [ "nothing" ] if* . ! prints "nothing"
unless* è l'idioma canonico del «valore o valore predefinito». Se il valore è veritiero, viene lasciato com'è; se è f, il valore viene eliminato e la quotation viene eseguita per impilare un sostituto:
"hello" [ "anonymous" ] unless* . ! => "hello"
f [ "anonymous" ] unless* . ! => "anonymous"
when* è la forma a un ramo di if*: esegue la sua quotation (con il valore ancora sullo stack) solo quando il valore è veritiero, e quando è f si limita a eliminare il valore. Usalo per integrare un risultato del tipo «la cosa, oppure f» in un valore accumulato, senza doverti preoccupare di gestire il caso f:
0 41 [ + ] when* . ! => 41 (truthy: 41 added to the running total)
0 f [ + ] when* . ! => 0 (falsy: f dropped, total left untouched)
condQuando hai diverse azioni alternative tra cui scegliere, cond (in combinators) è la scelta naturale. Prende un array di coppie { predicate body } ed esegue il corpo del primo predicato che produce un valore veritiero:
USING: combinators ;
: classify ( n -- label )
{
{ [ dup 0 < ] [ drop "negative" ] }
{ [ dup 0 = ] [ drop "zero" ] }
[ drop "positive" ]
} cond ;
Qualche dettaglio da tenere presente:
dup ... <test> è l'idioma abituale.drop dell'input per poi impilare il risultato.In questo esercizio scriverai del codice per analizzare la produzione di una catena di montaggio in una fabbrica di automobili. La velocità della catena di montaggio può andare da 0 (spenta) a 10 (massima).
Alla sua velocità minima diversa da zero (1), vengono prodotte 221 automobili ogni ora. La produzione aumenta in modo lineare con la velocità, quindi alla velocità 4 la linea produce 4 * 221 = 884 automobili all'ora. Tuttavia, velocità più alte aumentano la probabilità che vengano prodotte automobili difettose, che poi devono essere scartate.
Hai quattro compiti. Ognuno preleva dallo stack un singolo parametro intero (la velocità della catena di montaggio).
Definisci production-status in modo che restituisca "stopped" quando la velocità è 0 e "running" per qualsiasi altra velocità:
0 production-status .
! => "stopped"
3 production-status .
! => "running"
Definisci success-rate in modo che restituisca la probabilità che un pezzo venga prodotto senza errori:
0: 0.0
1 a 4: 1.0
5 a 8: 0.9
9: 0.8
10: 0.77
10 success-rate .
! => 0.77
Definisci production-rate-per-hour in modo che restituisca il tasso di produzione oraria della catena di montaggio, tenendo conto del tasso di successo.
Dovrai prima definire base-speed, la costante 221.
6 production-rate-per-hour .
! => 1193.4
Il valore restituito è un numero in virgola mobile.
Definisci working-items-per-minute in modo che restituisca quante automobili funzionanti vengono prodotte al minuto. Il risultato è un numero intero: le automobili incomplete non vengono conteggiate.
6 working-items-per-minute .
! => 19
Iscriviti a Exercism per imparare e padroneggiare Factor con 47 concetti163 esercizi e il mentoring di persone reali, tutto gratis.