2. Elm
2.4 Fallunterscheidungen und Boolesche Werte
Die If-Then-Else-Konstruktion in Elm haben Sie ja bereits im Repl-Fenster kennengelernt.
Für ein tieferes Verständnis brauchen wir allerdings boolesche Werte. Diese
sind Wahrheitswerte, also entweder True oder False.
x = 2x <= 3True : Boolx < 2False : Boolverb3 = "angeln"String.right 2 verb3 == "ln"True : Bool
Vergleichsoperatoren wie <, <=, >,
>=,
== geben Ihnen boolesche Werte. Es gibt auch vorgefertigte Funktionen, die
Ihnen ja/nein-Antworten liefern, zum Beispiel String.endsWith:
String.endsWith "en" "kochen"True : Bool
Beachten Sie die Signatur:
String.endsWith<function> : String -> String -> Bool
Natürlich können wir auch selbst Funktionen schreiben, die einen booleschen Wert zurückliefern.
Zum Beispiel eine Funktion, die überprüft, ob ihr Argument eine gerade Zahl ist. Hierfür
benötigen wir die vorgefertigte Funktion
modBy : Int -> Int -> Int, die den Rest nach der Division zurückgibt,
beispielsweise
modBy 3 101modBy 4 113
weil bei Division durch 3 die Zahl 10 einen Rest von 1 hinterlässt, und bei Division durch 4 die Zahl 11 einen Rest von 3. Eine Zahl ist nun gerade, wenn bei Division durch 2 ein Rest von 0 zurückbleibt. Daher:
isEven : Int -> BoolisEven n =if modBy 2 n == 0 thenTrueelseFalse
Es geht aber nur konziser. Der Vergleichsoperator == selbst liefert ja einen
booleschen Wert zurück. Und in diesem
Falle genau den, den wir wollen. Daher alternativ:
isEven : Int -> BoolisEven n =modBy 2 n == 0
Boolesche Operatoren
Genau wie wir ganze Zahlen mit+ oder * verknüpfen können, um neue
ganze Zahlen zu erhalten, so gibt es auch für boolesche Werte Operatoren. Die üblichsten
sind Und, Oder und Nicht. In Elm werden sie durch die Operatoren
&& für Und, || für Oder und not für Nicht
repräsentiert.
x = 2x >= 1 && x <= 3True : Bool
Beachten Sie, dass Ausdrücke wie x >= 1 zu einem Wert vom Typ Bool
auswerten und wir diesen Wert auch in einer Variable "abspeichern" können:
Als weiteres Beispiel schreiben wir eine Funktion, die im Körper boolesche Operatoren verwendet. Sie testet, ob die Eingabezahl gerade und positiv ist:a = x <= 3b = x < 0a && bFalse : Boola || bTrue : Bool
isEvenAndPositive : Int -> BoolisEvenAndPositive n =modBy 2 n == 0 && n > 0
diese hier testet, ob die Zahl gerade ist, aber nicht durch 4 teilbar:
isEvenButNotMultipleOfFour : Int -> BoolisEvenButNotMultipleOfFour n =modBy 2 n == 0 && modBy 4 n /= 0
mit /= testen Sie Ungleichheit; die nächste Funktion testet,
ob ein String mit "ern" oder "eln" endet:
endsInErnOrEln : String -> BoolendsInErnOrEln word =String.right 3 word == "ern" || String.right 3 word == "eln"
Schreiben Sie die Funktionen isEvenButNotMultipleOfFour und
endsInErnOrEln ohne boolesche Operatoren &&
und ||, nur mit geschachtelten if-Konstruktionen.
Die Auswertung eines if-Ausdrucks
Wenn ein Ausdruck der Form
if condition then expression1 else expression2
- es wird
conditionausgewertet - wenn
conditionzuTrueauswertet, dann wirdexpression1ausgewertet und das ist dann auch der Wert des ganzenif-Ausdrucks - wenn
conditionzuFalseauswertet, dann wirdexpression2ausgewertet.
Merken Sie sich also, dass von expression1 und expression2 immer nur
eines ausgewertet wird; dies ist insofern wichtig, als dass die Auswertung in der Realität oft
viel Zeil beanspruchen kann. Es wird hier also nur der Ausdruck ausgewertet, der auch benötigt
wird.
isLeapYear : Int -> Bool, die
überprüft, ob die gegebene (Jahres-)zahl ein Schaltjahr ist:
isLeapYear 2024TrueisLeapYear 1900False
Tip. Falls Sie die genaue Regel für Schaltjahre nicht kennen, googeln Sie!
nameOfWeekDay : Int -> String, die den
Namen des Wochentags ausgibt:
Was machen Sie, wenn die Zahl ungültig ist, beispielsweisenameOfWeekDay 2"Tuesday" : String
9?
weekDayFromName : String -> Int, der
den Namen des Wochentags erkennt:
weekDayFromName "Wednesday"3
Wie behandeln Sie ungültige Eingaben, also zum Beispiel
weekDayFromName "Thusday"?
Fallunterscheidungen mit case
Das mit den Wochentagen kriegen Sie eleganter mit einer sogenannten case-Konstruktion
hin:
weekDayFromName : String -> IntweekDayFromName day =case day of"Monday" ->1"Tuesday" ->2"Wednesday" ->3"Thursday" ->4"Friday" ->5"Saturday" ->6"Sunday" ->7_ ->-1
Eine case-Konstruktion lohnt sich immer dann, wenn Sie für einen Ausdruck (hier:
day) verschiedene
Werte abtesten. Beachten Sie die Zeile 75. Das _ entspricht dem else
und wird aktiv, wenn
keiner der vorherigen Fälle eingetreten ist. Meine Entscheidung, in diesem Falle -1 als
"Fehlercode" zurückzugeben,
gilt in Elm als ganz schlechter Stil. Ich erlaube es mir hier allerdings, weil wir
noch nicht gelernt haben, wie man solche "Fehler" behandelt.
case-Konstruktion
eine Funktion nameOfWeekDay : Int -> String -> String, die
den Namen des Wochentages in verschiedenen Sprachen ausgeben kann:
nameOfWeekDay 3 "English""Wednesday"nameOfWeekDay 4 "Polish""Czwartek"