Треки
/
Factor
Factor
/
Вправи
/
Автомобілі, збираймося!
Автомобілі, збираймося!

Автомобілі, збираймося!

Навчальна вправа

Вступ

Ця вправа знайомить з умовними конструкціями, тобто з вибором між двома або більше варіантами дій залежно від значення. Вона спирається на булеві значення (англ. Boolean), з якими ми познайомилися у вправі Інфільтрація Анналін, та на арифметику цілих чисел зі вправи Конвертація валют.

Слова порівняння

Усі вони містяться в math (а = - у kernel):

=  ( 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? (у math) - це скорочення для поширеної перевірки 0 =: він споживає число і кладе на стек те, чи було воно нулем:

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

Перевірки діапазону

between? (у math.order) перевіряє, чи лежить значення в діапазоні разом з його межами. Він стає в пригоді, коли дія залежить від того, у який діапазон потрапляє число:

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)

Ми часто бачимо його як предикат cond (dup 1 4 between?), щоб вибрати гілку за діапазоном, а не за одним значенням.

Квотації

Слова порівняння вище дають булеві значення. Щоб діяти за булевим значенням, ми передаємо умовній конструкції одну або кілька квотацій. Квотація - це фрагмент коду в квадратних дужках, [ ... ]. Коли ми її пишемо, код потрапляє на стек як значення, а не виконується, а слово на кшталт if потім вирішує, яку квотацію запустити.

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

Пізніша вправа розповість про квотації докладніше. А поки що читаймо [ ... ] як «код, який треба виконати для цієї гілки».

if, when, unless

if (у kernel) приймає булеве значення і дві квотації. Він виконує першу квотацію, коли булеве значення правдиве, і другу, коли воно неправдиве:

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

when виконує свою квотацію, лише коли булеве значення правдиве, а unless - лише коли воно неправдиве:

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

if*, when* і unless*

Три варіанти з kernel ставляться до булевого значення як до значення, яке варто зберегти, коли воно правдиве. Це стає в пригоді, коли слово повертає «річ або 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* - це форма з двома гілками. Правдиву гілку викликають зі значенням, що залишається на стеку, а неправдиву - без нього:

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

unless* - це класичний прийом «значення або типове значення». Якщо значення правдиве, його залишають як є. Якщо воно f, значення відкидають, і запускається квотація, яка кладе на стек замінник:

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

when* - це форма if* з однією гілкою: він виконує свою квотацію (зі значенням, що все ще на стеку) лише тоді, коли значення правдиве, і просто відкидає його, коли воно f. Він стане в пригоді, коли треба вкласти результат «річ або f» у поточне значення, не турбуючись про випадок f:

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

cond

Коли треба вибрати одну з кількох альтернативних дій, cond (у combinators) підходить найкраще. Він приймає масив пар { predicate body } і виконує тіло першого предиката, який дає правдиве значення:

USING: combinators ;

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

Кілька деталей, на які варто звернути увагу:

  • Пари перевіряються по порядку. Перемагає перший збіг.
  • Запис без предиката (просто одна квотація) у кінці діє як типовий варіант.
  • Кожен предикат оглядає вхідні дані, але має залишити стек даних таким, яким його знайшов. Зазвичай для цього використовують прийом dup ... <test>.
  • Тіло вибраної пари отримує той самий стек, який бачив предикат, тож зазвичай воно починається з того, що відкидає вхідні дані через drop і кладе на стек результат.

Вказівки

У цій вправі ми будемо писати код, щоб аналізувати виробництво на складальній лінії автомобільного заводу. Швидкість складальної лінії може бути в межах від 0 (вимкнено) до 10 (максимум).

За найнижчої ненульової швидкості (1) щогодини виробляється 221 автомобіль. Виробництво зростає лінійно зі швидкістю, тож за швидкості 4 лінія виробляє 4 * 221 = 884 автомобілі на годину. Однак вищі швидкості підвищують ймовірність виробництва бракованих автомобілів, які потім доводиться відкидати.

У нас є чотири завдання. Кожне з них бере зі стеку єдиний цілочисельний параметр: швидкість складальної лінії.

1. Повідомте, чи працює лінія

Визначте production-status так, щоб вона повертала "stopped", коли швидкість дорівнює 0, і "running" для будь-якої іншої швидкості:

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

2. Обчисліть коефіцієнт успішності

Визначте success-rate так, щоб вона повертала ймовірність того, що виріб виготовлено без помилок:

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

3. Обчисліть швидкість виробництва за годину

Визначте production-rate-per-hour так, щоб вона повертала швидкість виробництва складальної лінії за годину з урахуванням коефіцієнта успішності.

Спочатку нам потрібно визначити base-speed як константу 221.

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

Повернене значення має тип числа з плаваючою комою.

4. Обчисліть кількість придатних виробів, виготовлених за хвилину

Визначте working-items-per-minute так, щоб вона повертала кількість придатних автомобілів, виготовлених за хвилину. Результат має бути цілим числом; неповні автомобілі не враховуються.

6 working-items-per-minute .
! => 19
Редагувати через GitHub Посилання відкривається в новому вікні або вкладці
Factor Exercism

Час розпочати Автомобілі, збираймося!?

Зареєструйтеся на Exercism, щоб вивчати й опановувати Factor, а також 47 концепцій163 вправи та справжнє наставництво від людей, і все це безкоштовно.