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,
kann 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 formal 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 Test fehl ...
(a) Überlege welcher der drei Test fehlschlägt und begründe deine Vermutung.
(b) Überprüfe deine Vermutung in DrRacket und korrigiere die Fallunterscheidung um alle Test-Fä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öglichen Rückgabewerten.
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: Das ist die große Frage :o
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.
Gibt für alle natürlichen Zahlen, wenn zutreffend "zweistellig" oder "dreistellig" zurück.
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 zukaufendes 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")
)
) )