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 = 2
x <= 3
True : Bool
x < 2
False : Bool
verb3 = "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 10
1
modBy 4 11
3
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 -> Bool
isEven n =
if modBy 2 n == 0 then
True
else
False
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 -> Bool
isEven 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 = 2
x >= 1 && x <= 3
True : 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 <= 3
b = x < 0
a && b
False : Bool
a || b
True : Bool
isEvenAndPositive : Int -> Bool
isEvenAndPositive n =
modBy 2 n == 0 && n > 0
diese hier testet, ob die Zahl gerade ist, aber nicht durch 4 teilbar:
isEvenButNotMultipleOfFour : Int -> Bool
isEvenButNotMultipleOfFour 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 -> Bool
endsInErnOrEln 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
condition
ausgewertet - wenn
condition
zuTrue
auswertet, dann wirdexpression1
ausgewertet und das ist dann auch der Wert des ganzenif
-Ausdrucks - wenn
condition
zuFalse
auswertet, dann wirdexpression2
ausgewertet.
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 2024
True
isLeapYear 1900
False
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 -> Int
weekDayFromName 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"