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.
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
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.
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)
condWenn 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:
dup ... <test> ist das übliche Idiom.drop zu entfernen und das Ergebnis auf den Stack zu legen.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.
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"
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
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.
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
Melde dich bei Exercism an, um Factor mit 47 Konzepte163 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.