Ausdrücke auswerten Im Haskell-Interpreter können Ausdrücke direkt ausgewertet werden: Prelude> 42 42 Prelude> 5*3 15 Interpreter gibt Repräsentation des Wertes aus 1 Ausdrücke über Ganzzahlen • Konstanten: 1, 3, 42, 321432343243245 • Arithmetische Ausdrücke: 1+2, 4*2, 5+2*7, - 4 • Funktionsaufrufe: cos 2 2 Definitionen Eine Definition ist eine Gleichung: • name = expr z.B. pi = 3.14 Macht name im ganzen Programm verfügbar Progamm = Reihe von Definitionen 3 Definitionen laden Nach dem Start des Interpreters sind die Definitionen aus der Prelude verfügbar Weitere Definitionen müssen geladen werden: :load filename Haskell-Dateien sollten die Endung .hs haben Inhalt der Dateien: Reihe von Gleichungen 4 Bezeichner in Haskell • Erstes Zeichen: Kleinbuchstabe • Dann Buchstaben, Zahlen und ' • Bsp: abs, abs', splitAt, writeFile, zip3 5 Funktionsdefinition Mathematik: f(x) = cos(x) + 2 Haskell: name var ... = expr z.B. f x = cos x + 2 square x = x * x minus x y = x - y 6 Funktionsdefinition durch Fallaufzählung 1+1=2 1+2=3 2+3=5 In Haskell: add 1 1 = 2 add 1 2 = 3 add 2 5 = 7 Auch dabei Variablen möglich: add' 0 x = x add' 1 1 = 2 add' 1 2 = 3 Bei Überlappung: Erster von oben 7 Auswertung von Definitionen: Vereinfachen Wenn die rechte Seite einer Definition auf einen Ausdruck passt, ersetze den Ausdruck durch die linke Seite der Definition. 1 + 1 = 2 add 2 5 = 7 1 + (2 * pi) = 1 + 6.28 8 Auswertung von Funktionsaufrufen: Einsetzen Enthält die rechte Seite Variablen, so ersetze die Variablen durch die entsprechenden Argumente f (4 * 3) = cos (4 * 3) + 2 1 + (square (1 + 2)) = 1 + ((1 + 2) * (1 + 2)) minus (1 * 1) (4 / 2) = (1 * 1) - (4 / 2) 9 Normalform Kann ein Ausdruck nicht mehr weiter ausgewertet werden, so ist er in Normalform. Bsp: 12, 3.14, minus 10 Auswertungsreihenfolge Wichtige Eigenschaft der Funktionalen Programmierung: Wenn zwei Auswertungsfolgen terminieren, so liefern sie dieselbe Normalform. 11 Bsp: Alternative Auswertungsreihenfolgen square (3 + 4) = square 7 = 7*7 = 49 square (3 + 4) = (3 + 4) * (3 + 4) = 7 * (3 + 4) = 7 * 7 = 49 square (3 + 4) = (3 + 4) * (3 + 4) = (3 + 4) * 7 = 7 * 7 = 49 12 Auswertungsstrategie Eine Auswertungsstrategie legt eine bestimmte Auswertungsreihenfolge fest. Beispiele: Call-by-Name, Call-by-Value Später: Lazy-Evaluation als Strategie für Haskell 13 Werte Ein Ausdruck beschreibt einen Wert Mögliche Arten von Werte: Zahlen, Boolean, Zeichen, Tupel, Listen, Funktionen, ... 14 Kanonische Repräsentation Werte sind abstrakt, Ausdrücke repräsentieren Werte Haskell-Interpreter gibt für einen Wert seine kanonische Repräsentation aus Manche Werte haben keine kanonische Rep., z.B. Funktionen oder π 15 Bottom Manche Ausdrücke repräsentieren keine wohldefinierten Werte Programm: infinity = infinity + 1 infinity 1 / 0 Spezieller Wert: ⊥ 16 Striktheit Wenn f ⊥ = ⊥, dann ist f eine strikte Funktion, sonst ist f eine nicht-strikte Funktion Lazy-Evaluation erlaubt es, nicht-strikte Funktion zu definieren: three x = 3 three infinity = 3 17 Rekursive Definitionen fact n = if n == 0 then 1 else n * fact (n - 1)) Auswertung mit Vereinfachen und Einsetzen: fact 1 = if 1 == 0 then 1 else 1 * fact (1 - 1) = 1 * fact (1 - 1) = 1 * (if (1 - 1) == 0 then 1 else (1 - 1) * fact ((1 = 1 * (if (0 == 0) then 1 else ... = 1 * 1 = 1 18 Typen Typ = Menge von Werten Typ für Zahlen: Integer Typ für Funktionen: t1 ->... tN -> tR Wobei t1... tN die Typen der Argumente und tR der Typ des Ergebnisses sind. Bsp: Typ von add: Integer -> Integer -> Integer Kommando :type expr liefert Typ des Ausdrucks expr 19 Typsignaturen Bei einer Definition kann der Typ mit angegeben werden = Typsignatur. Syntax: name :: typ Bsp: square :: Integer -> Integer square x = x * x 20 Vorteile von Typsignaturen • Teil des Designs: Man macht sich erste Gedanken über Ein- und Ausgabe • Bessere Fehlermeldungen, denn der Compiler liest die Signaturen zuerst • Teil der Dokumentation: Leser kennt sofort den Typ der Ein/Ausgaben ⇒ Bei den Lösungen der Übungsaufgaben immer angeben 21 Funktionen sind einstellig Funktionen in Haskell sind in Wahrheit einstellig: f x y = e definiert eine einstellige Funktion, die eine einstellige Funktion zurückgibt: fTwo = f 2 hat Typ Integer ->> Integer fTwo 3 ≡ (f 2) 3 ≡ f 2 3 Currying 22 Funktionstypen -> ist rechtsassoziativ Integer -> Integer -> Integer ist gleich Integer -> (Integer -> Integer) 23 Currying erleichtert Wiederverwendung twice :: (Integer -> Integer) -> Integer -> Integer twice f x = f (f x) quad :: Integer -> Integer quad = twice square 24 Boolsche Werte Eigener Typ: Bool Werte des Typs: • Wahr True • Falsch False 25 Boolsche Werte Operatoren: &&, ||, not, == exOr :: Bool -> Bool -> Bool exOr x y = (x || y) && not (x && y) Alternative Definition: exOr True x = not x exOr False x = x 26 Bedingte Ausdrücke Ganz normales if Syntax: if test-expr then cons-expr else alt-expr • test-expr muss vom Typ Boolean sein • cons-expr und alt-expr müssen vom gleichen Typ sein 27 Auswertung für bedingte Ausdrücke Wenn test-expr True ist, ersetze den if-Ausdruck durch cons-expr, wenn test-expr False ist, ersetze den if-Ausdruck durch alt-expr. Bsp: 1 + (if True 4 else 42) = 1 + 4 = 5 neg :: Bool -> Bool neg test = if test False else True 28 Operatoren Def: Ein Operator ist eine Funktion, die infix aufgerufen wird In Haskell wird jede binäre Funktion durch Backquotes zum Operator: Bsp: 3 `smallerc` 4 entspricht smallerc 3 4 Auch in Definition möglich Umgekehrt wird jeder Operator in Klammern zur binären Funktion: Bsp: (+) 3 4 entspricht 3 + 4 29 Sektionen Sektion: Binärer Operator auf nur ein Argument angewendet. Ergebnis ist eine Funktion: (* (> (1 (+ 2) 0) /) 1) ----- Verdoppeln Test auf positive Zahl Kehrwert Nachfolger Aber: (- 2) ist unäre Negation 30 Funktionskomposition In der Mathematik: f ⋅ g(x) = f(g(x)) In Haskell: Operator . Es gilt also (f . g) x ist gleich f (g x) 31