Tracks
/
Factor
Factor
/
Übungen
/
Autos, montiert!
Autos, montiert!

Autos, montiert!

Lernübung

Einführung

Diese Übung führt dich in bedingte Anweisungen ein: Du wählst zwischen zwei oder mehr Handlungswegen, je nach einem Wert. Sie baut auf den booleschen Werten auf, die du in Annalyn's Infiltration kennengelernt hast, und auf der Ganzzahl-Arithmetik aus Currency Conversion.

Vergleichswörter

Alle diese Wörter findest du in math (und in kernel für =):

=  ( 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) ist eine Kurzform für den üblichen 0 =-Test: Es verbraucht die Zahl und legt auf den Stack, ob sie null war:

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

Bereichsprüfungen

between? (in math.order) prüft, ob ein Wert in einen inklusiven Bereich fällt. Es ist praktisch, wenn eine Aktion davon abhängt, in welchen Bereich eine Zahl fällt:

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)

Du siehst es oft als cond-Prädikat, etwa dup 1 4 between?, um einen Zweig nach Bereich statt nach einem einzelnen Wert auszuwählen.

Quotations

Die Vergleichswörter oben erzeugen boolesche Werte. Um auf einen booleschen Wert zu reagieren, übergibst du der bedingten Anweisung eine oder mehrere Quotations. Eine Quotation ist ein Code-Schnipsel in eckigen Klammern, [ ... ]. Wenn du sie schreibst, wird der Code als Wert auf den Stack gelegt, statt ausgeführt zu werden. Ein Wort wie if entscheidet dann, welche Quotation ausgeführt wird.

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

Eine spätere Übung behandelt Quotations ausführlich. Lies [ ... ] vorerst als „den Code, der für diesen Zweig ausgeführt wird“.

if, when, unless

if (in kernel) nimmt einen booleschen Wert und zwei Quotations. Es führt die erste Quotation aus, wenn der boolesche Wert wahr ist, und die zweite, wenn er falsch ist:

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

when führt seine Quotation nur aus, wenn der boolesche Wert wahr ist; unless nur, wenn er falsch ist:

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

if*, when* und unless*

Drei Kernel-Varianten behandeln den booleschen Wert als Wert, den es zu behalten lohnt, wenn er wahr ist. Das ist nützlich, wenn ein Wort „die Sache oder f“ zurückgibt:

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* ist die Zwei-Zweig-Form. Der wahre Zweig wird aufgerufen, während der Wert noch auf dem Stack liegt; der falsche Zweig wird ohne ihn aufgerufen:

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

unless* ist das kanonische Idiom für „Wert oder Standardwert“. Ist der Wert wahr, bleibt er unangetastet; ist er f, wird der Wert verworfen und die Quotation läuft, um einen Ersatzwert auf den Stack zu legen:

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

when* ist die Ein-Zweig-Form von if*: Es führt seine Quotation nur dann aus, wenn der Wert wahr ist, während der Wert noch auf dem Stack liegt, und verwirft den Wert einfach, wenn er f ist. Nutze es, um ein Ergebnis der Art „die Sache oder f“ in einen laufenden Wert einzufalten, ohne dich um den f-Fall kümmern zu müssen:

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

cond

Wenn du zwischen mehreren alternativen Aktionen wählen musst, ist cond (in combinators) die natürliche Wahl. Es nimmt ein Array von { predicate body }-Paaren und führt den Body des ersten Prädikats aus, das einen wahren Wert liefert:

USING: combinators ;

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

Ein paar Details, die es sich zu beachten lohnt:

  • Die Paare werden der Reihe nach durchprobiert. Der erste Treffer gewinnt.
  • Ein Eintrag ohne Prädikat (nur eine einzelne Quotation) am Ende dient als Standardfall.
  • Jedes Prädikat untersucht die Eingabe, sollte den Datenstack aber so hinterlassen, wie es ihn vorgefunden hat. dup ... <test> ist das übliche Idiom.
  • Der Body des gewählten Paares erhält denselben Stack, den das Prädikat gesehen hat, also beginnt er üblicherweise damit, die Eingabe mit drop zu entfernen und das Ergebnis auf den Stack zu legen.

Anleitung

In dieser Übung schreibst du Code, um die Produktion eines Fließbands in einer Autofabrik zu analysieren. Die Geschwindigkeit des Fließbands kann von 0 (aus) bis 10 (Maximum) reichen.

Bei der niedrigsten Geschwindigkeit ungleich null (1) werden 221 Autos pro Stunde produziert. Die Produktion steigt linear mit der Geschwindigkeit, bei Geschwindigkeit 4 produziert das Band also 4 * 221 = 884 Autos pro Stunde. Höhere Geschwindigkeiten erhöhen jedoch die Wahrscheinlichkeit, dass fehlerhafte Autos produziert werden, die dann aussortiert werden müssen.

Du hast vier Aufgaben. Jede nimmt einen einzelnen ganzzahligen Parameter vom Stack: die Geschwindigkeit des Fließbands.

1. Melde, ob das Band läuft

Definiere production-status, sodass es "stopped" zurückgibt, wenn die Geschwindigkeit 0 ist, und "running" für jede andere Geschwindigkeit:

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

2. Berechne die Erfolgsrate

Definiere success-rate, sodass es die Wahrscheinlichkeit zurückgibt, dass ein Teil fehlerfrei produziert wird:

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

3. Berechne die Produktionsrate pro Stunde

Definiere production-rate-per-hour, sodass es die Produktionsrate des Fließbands pro Stunde zurückgibt und dabei die Erfolgsrate berücksichtigt.

Du musst zuerst base-speed definieren, die Konstante 221.

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

Der zurückgegebene Wert ist eine Gleitkommazahl.

4. Berechne die Anzahl der funktionierenden Teile, die pro Minute produziert werden

Definiere working-items-per-minute, sodass es zurückgibt, wie viele funktionierende Autos pro Minute produziert werden. Das Ergebnis ist eine Ganzzahl, unvollständige Autos werden nicht gezählt.

6 working-items-per-minute .
! => 19
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab
Factor Exercism

Bereit, mit Autos, montiert! zu starten?

Melde dich bei Exercism an, um Factor mit 47 Konzepte163 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.