Percursos
/
Factor
Factor
/
Exercícios
/
Carros, à montagem!
Carros, à montagem!

Carros, à montagem!

Exercício de aprendizagem

Introdução

Este exercício introduz as condicionais: escolher entre duas ou mais linhas de ação com base num valor. Baseia-se nos booleans que conheceste na Infiltração da Annalyn e na aritmética de números inteiros da Conversão de Moeda.

Palavras de comparação

Todas estas palavras estão em math (e em kernel no caso do =):

=  ( 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? (em math) é um atalho para o teste habitual 0 =: consome o número e coloca na pilha se ele era zero:

zero? ( n -- ? )    ! t when n is 0

Verificações de intervalo

between? (em math.order) testa se um valor está dentro de um intervalo inclusivo. É útil quando uma ação depende da faixa em que um número cai:

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)

Vais vê-lo muitas vezes como predicado de um cond (dup 1 4 between?) para escolher um ramo por intervalo em vez de por um único valor.

Quotations

As palavras de comparação acima produzem booleans; para agir sobre um boolean, entregas à condicional uma ou mais quotations. Uma quotation é um fragmento de código entre parênteses retos, [ ... ]. Ao escrevê-la, colocas o código na pilha como um valor em vez de o executar: uma palavra como if decide depois qual quotation executar.

[ neg ]   ! a quotation that negates the top of the stack
[ ]       ! the empty quotation — does nothing

Um exercício mais adiante aborda as quotations na totalidade; por agora, lê [ ... ] como «o código a executar neste ramo».

if, when, unless

if (em kernel) recebe um boolean e duas quotations. Executa a primeira quotation quando o boolean é verdadeiro e a segunda quando é falso:

if ( ? then-quot else-quot -- )
: abs ( x -- y ) dup 0 < [ neg ] [ ] if ;

when executa a sua quotation apenas quando o boolean é verdadeiro; unless apenas quando é falso:

when   ( ? quot -- )
unless ( ? quot -- )

if*, when* e unless*

Três variantes do kernel tratam o boolean como um valor que vale a pena manter quando é verdadeiro. Isto é útil quando uma palavra devolve «a coisa, 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* é a forma de dois ramos. O ramo verdadeiro é chamado com o valor ainda na pilha; o ramo falso é chamado sem ele:

42 [ ] [ "nothing" ] if* .   ! prints 42
f  [ ] [ "nothing" ] if* .   ! prints "nothing"

unless* é a forma canónica de «valor ou predefinição». Se o valor for verdadeiro, fica como está; se for f, o valor é descartado e a quotation é executada para colocar um substituto:

"hello" [ "anonymous" ] unless* .   ! => "hello"
f       [ "anonymous" ] unless* .   ! => "anonymous"

when* é a forma de um só ramo de if*: executa a sua quotation (com o valor ainda na pilha) apenas quando o valor é verdadeiro, e limita-se a descartar o valor quando é f. Recorre a ele para incorporar um resultado do tipo «a coisa, ou f» num valor acumulado, sem te preocupares em tratar o caso f:

0 41 [ + ] when* .   ! => 41   (truthy: 41 added to the running total)
0 f  [ + ] when* .   ! => 0    (falsy: f dropped, total left untouched)

cond

Quando tens várias ações alternativas entre as quais escolher, cond (em combinators) é a escolha natural. Recebe um array de pares { predicate body } e executa o corpo do primeiro predicado que produz um valor verdadeiro:

USING: combinators ;

: classify ( n -- label )
    {
        { [ dup 0 <  ] [ drop "negative" ] }
        { [ dup 0 =  ] [ drop "zero"     ] }
        [ drop "positive" ]
    } cond ;

Alguns detalhes que vale a pena notar:

  • Os pares são testados por ordem. O primeiro que corresponde vence.
  • Uma entrada sem predicado (apenas uma quotation) no fim funciona como predefinição.
  • Cada predicado inspeciona o valor de entrada, mas deve deixar a pilha de dados como a encontrou: dup ... <test> é a expressão habitual.
  • O corpo do par escolhido recebe a mesma pilha que o predicado viu, por isso começa habitualmente por fazer drop do valor de entrada e colocar o resultado.

Instruções

Neste exercício vais escrever código para analisar a produção de uma linha de montagem numa fábrica de automóveis. A velocidade da linha de montagem pode ir de 0 (desligada) a 10 (máxima).

À sua velocidade não nula mais baixa (1), são produzidos 221 automóveis por hora. A produção aumenta linearmente com a velocidade, por isso, à velocidade 4, a linha produz 4 * 221 = 884 automóveis por hora. No entanto, velocidades mais altas aumentam a probabilidade de serem produzidos automóveis com defeito, que depois têm de ser descartados.

Tens quatro tarefas. Cada uma retira da pilha um único parâmetro inteiro: a velocidade da linha de montagem.

1. Indicar se a linha está a funcionar

Define production-status para devolver "stopped" quando a velocidade é 0 e "running" para qualquer outra velocidade:

0 production-status .
! => "stopped"
3 production-status .
! => "running"

2. Calcular a taxa de sucesso

Define success-rate para devolver a probabilidade de um item ser produzido sem erro:

  • 0: 0.0
  • 1 a 4: 1.0
  • 5 a 8: 0.9
  • 9: 0.8
  • 10: 0.77
10 success-rate .
! => 0.77

3. Calcular a taxa de produção por hora

Define production-rate-per-hour para devolver a taxa de produção da linha de montagem por hora, tendo em conta a taxa de sucesso.

Vais precisar de definir base-speed primeiro, a constante 221.

6 production-rate-per-hour .
! => 1193.4

O valor devolvido é um número de vírgula flutuante.

4. Calcular o número de itens funcionais produzidos por minuto

Define working-items-per-minute para devolver quantos automóveis funcionais são produzidos por minuto. O resultado é um número inteiro: os automóveis incompletos não são contados.

6 working-items-per-minute .
! => 19
Editar via GitHub A ligação abre numa nova janela ou separador
Factor Exercism

Estás pronto para começar Carros, à montagem!?

Inscreve-te no Exercism para aprenderes e dominares Factor com 47 conceitos163 exercícios, e mentoria humana real, tudo grátis.