Este ejercicio presenta los condicionales, es decir, la elección entre dos o más cursos de acción en función de un valor. Se apoya en los booleanos que conociste en La infiltración de Annalyn y en la aritmética con números enteros de Conversión de divisas.
Todas ellas se encuentran en math (y en kernel para =):
= ( 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? (en math) es una forma abreviada de la prueba habitual 0 =:
consume el número y apila si era cero:
zero? ( n -- ? ) ! t when n is 0
between? (en math.order) comprueba si un valor cae dentro de
un intervalo inclusivo. Resulta útil cuando una acción depende de la franja en la
que cae un número:
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)
A menudo lo verás como predicado de cond (dup 1 4 between?) para elegir
una rama por intervalo en lugar de por un único valor.
Las palabras de comparación anteriores producen booleanos; para actuar sobre un
booleano, le pasas al condicional una o varias quotations. Una quotation es un
fragmento de código encerrado entre corchetes, [ ... ]. Al escribirla, se apila
el código como un valor en lugar de ejecutarlo, y una palabra como if decide
después qué quotation ejecutar.
[ neg ] ! a quotation that negates the top of the stack
[ ] ! the empty quotation — does nothing
Un ejercicio posterior trata las quotations en detalle; por ahora, lee
[ ... ] como «el código que hay que ejecutar para esta rama».
if, when, unless
if (en kernel) recibe un booleano y dos quotations. Ejecuta la
primera quotation cuando el booleano es verdadero y la segunda cuando es falso:
if ( ? then-quot else-quot -- )
: abs ( x -- y ) dup 0 < [ neg ] [ ] if ;
when ejecuta su quotation solo cuando el booleano es verdadero; unless, solo
cuando es falso:
when ( ? quot -- )
unless ( ? quot -- )
if*, when* y unless*
Tres variantes de kernel tratan el booleano como un valor que merece conservarse
cuando es verdadero, algo útil cuando una palabra devuelve «la cosa, o 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* es la forma de dos ramas. La rama verdadera se llama con el valor todavía
en la pila; la rama falsa se llama sin él:
42 [ ] [ "nothing" ] if* . ! prints 42
f [ ] [ "nothing" ] if* . ! prints "nothing"
unless* es el modismo canónico de «valor o predeterminado». Si el valor es
verdadero, se deja tal cual; si es f, el valor se descarta y la quotation se
ejecuta para apilar un sustituto:
"hello" [ "anonymous" ] unless* . ! => "hello"
f [ "anonymous" ] unless* . ! => "anonymous"
when* es la forma de una sola rama de if*: ejecuta su quotation (con el valor
todavía en la pila) solo cuando el valor es verdadero, y simplemente descarta el
valor cuando es f. Úsala para incorporar un resultado de tipo «la cosa, o f»
a un valor acumulado sin molestarte en gestionar el caso f:
0 41 [ + ] when* . ! => 41 (truthy: 41 added to the running total)
0 f [ + ] when* . ! => 0 (falsy: f dropped, total left untouched)
condCuando tienes varias acciones alternativas entre las que elegir, cond
(en combinators) es la opción natural. Recibe un array de pares
{ predicate body } y ejecuta el cuerpo del primer predicado que produzca un
valor verdadero:
USING: combinators ;
: classify ( n -- label )
{
{ [ dup 0 < ] [ drop "negative" ] }
{ [ dup 0 = ] [ drop "zero" ] }
[ drop "positive" ]
} cond ;
Algunos detalles que conviene tener en cuenta:
dup ... <test> es el modismo habitual.drop de la entrada y apilando el resultado.En este ejercicio vas a escribir código para analizar la producción de una
cadena de montaje en una fábrica de coches. La velocidad de la cadena de montaje
puede ir de 0 (apagada) a 10 (máxima).
A su velocidad más baja distinta de cero (1), se producen 221 coches cada
hora. La producción aumenta de forma lineal con la velocidad, así que a
velocidad 4 la cadena produce 4 * 221 = 884 coches por hora. Sin embargo,
las velocidades más altas aumentan la probabilidad de que se produzcan coches
defectuosos, que después hay que desechar.
Tienes cuatro tareas. Cada una toma de la pila un único parámetro entero: la velocidad de la cadena de montaje.
Define production-status para que devuelva "stopped" cuando la velocidad
sea 0 y "running" para cualquier otra velocidad:
0 production-status .
! => "stopped"
3 production-status .
! => "running"
Define success-rate para que devuelva la probabilidad de que un artículo se
produzca sin errores:
0: 0.0
1 a 4: 1.0
5 a 8: 0.9
9: 0.8
10: 0.77
10 success-rate .
! => 0.77
Define production-rate-per-hour para que devuelva la tasa de producción por
hora de la cadena de montaje, teniendo en cuenta la tasa de éxito.
Primero tendrás que definir base-speed, la constante 221.
6 production-rate-per-hour .
! => 1193.4
El valor devuelto es un número de coma flotante.
Define working-items-per-minute para que devuelva cuántos coches en buen
estado se producen por minuto. El resultado es un número entero: los coches
incompletos no se cuentan.
6 working-items-per-minute .
! => 19
Regístrate en Exercism para aprender y dominar Factor con 47 conceptos163 ejercicios y mentoría humana real, todo gratis.