Strukturierung: Fallunterscheidungen
Wenn wir Funktionen schreiben, welche sich in Abhängigkeit der Übergabedaten unterschiedlich verhalten sollen, benötigen wir Fallunterscheidungen, um dieses Verhalten umzusetzen.
Die allgemeine Fallunterscheidung
Eine allgemeine Fallunterscheidung wird in Racket mit einem
(cond ...)
-Ausdruck umgesetzt.
Dieser enthält beliebig viele Fälle,
die jeweils aus einer Bedingung (ein Ausdruck mit booleschem Rückgabewert) und einem zugehörigen Rückgabewert bestehen.
Wenn die Bedingung #t
ergibt, wird der zugehörige Rückgabewert als Ergebnis der Funktion zurückgegeben.
Wenn nicht sichergestellt werden kann, dass mindestens eine der Bedingungen zu #t
ausgewertet wird,
muss ein else
-Fall hinzugefügt werden.
Beispielfunktion mit einer allgemeinen Fallunterscheidung:
;Bestimmt ob eine Zahl positiv oder negativ ist
(: positiv-oder-negativ (real -> string))
(check-expect (positiv-oder-negativ -0.2) "negativ")
(check-expect (positiv-oder-negativ 0) "weder positiv noch negativ")
(check-expect (positiv-oder-negativ 12.7) "positiv")
(define positiv-oder-negativ
(lambda (zahl)
(cond
([< zahl 0] "negativ")
([= zahl 0] "weder positiv noch negativ")
([> zahl 0] "positiv")
)
) )
Aufgabe 1: Fälle in der allgemeinen Fallunterscheidung
Welche der folgenden Fallunterscheidungen sind korrekt? Begründe deine Entscheidung.
(a)
(cond
([< zahl 0] 0)
([= zahl 0] 1)
([> zahl 0] 0)
)
(b)
(cond
([+ a 0] "zulässig")
([- a 0] "zulässig")
([* a 0] "zulässig")
([/ a 0] "unzulässig")
)
(c)
(cond
([= (string-length text) 0] "leerer String")
([<= 100 (string-length text)] "großer String")
([>= 10 (string-length text)] "kleiner String")
([string=? text text] (string-append text "!"))
)
(d)
(cond
([string=? "minus"] (- x 1))
([string=? "plus"] (+ x 1))
([string-append "plus" "minus"] x)
(else 0)
)
Aufgabe 2: Auswertungsreihenfolge in der allgemeinen Fallunterscheidung
Ein Student hat in einer Prüfung zu Racket die folgende Funktion geschrieben:
;Funktion die die nächst größere Zahl als string zurückgibt bis maximal "fünf"
(: naechsteZahl (natural -> string))
(check-expect (naechsteZahl 7) "fünf")
(check-expect (naechsteZahl 3) "vier")
(check-expect (naechsteZahl 0) "eins")
(define naechsteZahl
(lambda (zahl)
(cond
([< zahl 4] "vier")
([< zahl 3] "drei")
([< zahl 2] "zwei")
([< zahl 1] "eins")
(else "fünf")
)
) )
Allerdings schlägt einer der drei Tests fehl.
(a) Überlege, welcher der drei Tests fehlschlägt und begründe deine Vermutung.
(b) Überprüfe deine Vermutung in DrRacket und korrigiere die Fallunterscheidung, um alle Testfälle zu bestehen.
Die binäre Fallunterscheidung
Eine binäre Fallunterscheidung wird in Racket mit einem
(if ...)
-Ausdruck umgesetzt.
Dieser enthält eine Bedingung (ein Ausdruck mit booleschem Rückgabewert) und zwei mögliche Rückgabewerte.
Wenn die Bedingung #t
ergibt, wird der erste Rückgabewert als Ergebnis der Funktion zurückgegeben,
wenn die Bedingung #f
ergibt, der zweite.
Beispielfunktion mit einer binären Fallunterscheidung:
;Bestimmt ob eine Klassenarbeit mit der erreichten Anzahl an MSS-Notenpunkten bestanden wurde.
(: bestanden? (natural -> boolean))
(check-expect (bestanden? 4) #f)
(check-expect (bestanden? 5) #t)
(define bestanden?
(lambda (punkte)
(if [< punkte 5] #f #t)
) )
Aufgabe 3: Anwendung der Faustregeln
Welche der beiden Fallunterscheidungsarten eignet sich (nach unseren Faustregeln) für die folgenden Funktionen:
Eine Funktion, die je nach Ergebnis eines Münzwurfs unterschiedliches Verhalten aufweist.
Eine Funktion, die je nach Ergebnis eines Würfelwurfs unterschiedliches Verhalten aufweist.
Eine Funktion, die für alle natürlichen Zahlen, wenn zutreffend, "zweistellig" oder "dreistellig" zurückgibt.
Nach Abschluss des Abiturs wird eine Funktion veröffentlicht, mit welcher man prüfen kann,
ob eine Abiturnote besser als der Durchschnitt ist.
Ein Online-Unternehmen verkauft Android- und iOS-Smartphones. Sie veröffentlichen
eine Funktion, die für jedes zukaufende Smartphone einen Preis zurückgibt.
Aufgabe 4: Verkettung binärer Fallunterscheidung
Wir haben nun zwei Arten von Fallunterscheidungen kennengelernt, die für unterschiedliche Zwecke geeignet sind. Auch haben wir bereits gezeigt, dass wir eine allgemeine Fallunterscheidung mit zwei Fällen ohne Probleme in eine binäre Fallunterscheidung überführen können. Doch wie sieht es aus, wenn wir für mehrere Fälle nur binäre Fallunterscheidungen verwenden dürfen?
(a) Ändere den Funktionskörper der Funktion btb-binaer
so, dass nur noch binäre Fallunterscheidungen verwendet werden.
;Bestimmt den pH-Zustand anhand der Färbung des pH-Indikators Bromthymolblau (BTB)
(: btb-binaer (string -> string))
(check-expect (btb-binaer "gelb") "sauer")
(check-expect (btb-binaer "grün") "neutral")
(check-expect (btb-binaer "blau") "alkalisch")
(check-expect (btb-binaer "rot") "ungültiges Übergabedatum")
(define btb-binaer
(lambda (farbe)
(cond
([string=? "gelb" farbe] "sauer")
([string=? "grün" farbe] "neutral")
([string=? "blau" farbe] "alkalisch")
(else "ungültiges Übergabedatum")
)
) )