Ganzzahlen beschränkter Länge Der Typ Int umfasst Ganzzahlen beschränkter Länge Operatoren: +,*,^,Funktionen: div, mod, abs, negate Vergleichsoperatoren: >,>=,==,/=,<=,< Auf den Folien jetzt immer Int. 1 Überladung Beobachtungen: • Alle Zahlenoperatoren und Funktionen arbeiten auf Int und Integer. • == und /= arbeiten auf Bool, Int und Integer (und vielen mehr) Überladung: Der gleiche Name wird für verschiedene Operationen verwendet. Auch die Zahlenkonstanten sind überladen Später: Überladung selbst definieren 2 Guards Mathematik: abs(x) = x, falls x >= 0 -x, falls x < 0 In Haskell: abs x | x >= 0 = x abs x | x < 0 = -x Guard gibt an, ob eine Gleichung ausgewählt werden soll 3 Syntax und Auswertung von Guards Syntax: name pat+ | guard-expr = expr • guard-expr muss den Typ Bool haben. • Auswahl der Gleichung erfolgt noch immer von oben nach unten. • Passen die Argumente auf die Muster pat+ so ersetze die Parameter in guard-expr und in expr durch die Argumente. • Wenn guard-expr gleich True ist, so passt die Gleichung, wenn guard-expr gleich False ist, so passt die Gleichung nicht. 4 Zeichen • Typ: Char • Literale: Zeichen zwischen Hochkommata, z.B. 'a', '3' • Spezailfälle: '\t', '\n','\\','\'','\"' • Modul Char stellt einige Funktionen für Zeichen bereit 5 Fließkommazahlen • Typ: Float • Literale: 0.235, 231.61e7, -2.33 • Eingebaute Funktionen: Arithmetik, Trigonometrie, ... • Funktionen, Operatoren und Konstanten sind überladen. 1.0 + 2.2 = 3.2 abs -2.2 = 2.2 round 1 = 1 6 Typkonversion für Zahlen Automatische Typkonversion findet nicht statt! • 1 + 2.2 = 3.2,denn 1 ist überladen • round 1 + 2.2 ⇒ Typfehler, denn round liefert Int • Typen der Argumente müssen gleich sein, denn sie legen Ergebnistyp fest 7 Layout-Syntax • Das Layout (die Einrückung) eines Haskell-Programms bestimmt die Syntax. • Bei Definitionen: Erster Buchstabe beginnt Definition Buchstabe mit gleicher Einrückung beendet Definition foo x = x + x - 3 g y = y 8 Layout-Syntax • Explizites Ende mit ; möglich • Bei Guards bestimmen | und = die Syntax: threeMax x y z | x >= y && x >= z = x | y >= z = y | otherwise = z 9 Konstruktion von Funktionen Zuerst: 1. Kurze Beschreibung als Kommentar 2. Typsignatur angeben 3. Beispiele angeben In Zukunft immer bei den Abgaben! 10 Konstruktion rekursiver Funktionen über Zahlen • Induktive Definition von Zahlen: 0 ist eine natürliche Zahl Der Nachfolger einer natürlichen Zahl ist eine nat. Zahl Eine Funktion heißt primitiv-rekurisiv wenn sie definiert ist durch Angabe des Wertes bei Null und durch eine Vorschrift, die besagt, wie der Wert für n aus dem Wert für n - 1 berechnet wird. 11 Schablone für primitiv-rekurisive Funktionen f n | n == 0 = ... | n > 0 = ... f (n - 1) ... D.h. annehmen, dass f (n - 1) bereits die Spezifikation erfüllt. 12 Konstruktion allgemein rekursiver Funktionen über Zahlen Schablone: f n | n == 0 = ... | n > 0 = ... f k ... Dabei annehmen, dass f k bereits die Spezifikation erfüllt. Achtung: Terminierung ist hier nicht garantiert! 13 Fehlermeldung ausgeben fac fac | | | :: Int -> Int n n == 0 = 1 n > 0 = n * fac (n - 1) * n otherwise = error "fac mit negativem Argument" 14 Beispiele als Testfälle • Black-Box-Tests: später und mit Tool • White-Box-Tests: Testfälle formulieren anhand der Definition Bei rekursiven Funktionen Basisfall und rekursiven Fall/Fälle Bei Guards alle Fälle abdecken Beispiele sind ebenfalls Testfälle, am besten als White-Box-Tests formulieren three x = 3 testThree = three 23 == 3 && three 34 == 3 15 Tupel und Listen • Bis jetzt: Nur Basistypen • Jetzt: Zusammengesetzte Typen Tupel: Feste Anzahl von Werten unterschiedlichen Typs Listen: Beliebige Anzahl von Werten gleichen Typs 16 Tupel • Mathe: (1,2) ∈ Int X Int • Zusammengesetzte Typen fester Länge Der Typ (t1,t2,...,tN) umfasst Tupel (v1,v2,...,vN) mit v1::t1,v2::t2,...,vN::tN (1,True) :: (Int,Bool) (1.2,'a',) :: (Float,Char,Int) • Die Syntax für Typen und Werte ist also gleich 17 Beispiele origin :: (Int,Int) origin = (0,0) makePoint :: Int -> Int -> (Int,Int) makePoint x y = (x,y) 18 Muster für Tupel Tupel können als Muster in Funktionsdefinitionen verwendet werden. pointAddX :: (Int,Int) -> Int -> (Int,Int) pointAddX (x,y) deltaX = (x + deltaX,y) point3dAddY :: (Int,Int,Int) -> Int -> (Int,Int,Int) point3dAddY (x,y,z) deltaY = (x,y+deltaY,z) 19 Nochmal Currying • Mathe: g(x,y) = 2 * x + y • Haskell: g (x,y) = 2 * x + y • Haskell, mit Currying: gc x y = 2 * x + y curry :: ((Int,Int) -> Int) -> Int -> Int -> Int curry f x y = f(x,y) gc = curry g P.S. Currying heißt auch Schönfinkeln 20 Einschub: Aussagen über Programmen beweisen • Funktionen sind als Gleichungen formuliert • Diese Gleichungen können auch in Beweisen verwendet werden • Freie Variabeln der Aussagen sind ∀-quantifiziert Z.Z: square x ≡ x 2 Def. Potenzieren Def.* Def.square 2 = x = x * x = x⋅x square x 21 Listen • Beliebige Anzahl von Werten gleichen Typs • Für jeden Typ t gibt es einen Typ [t] von Listen über t • Kanonische Repräsentation: [x,y,...] • Die leere Liste: [] • Beispiele: [1,2] :: [Int] ['a','b','c'] :: [Char] 22 Einschub: Typsynonyme • Auch für Typen können Namen definiert werden • Syntax: type name = Typ • Definiert name als Typsynonym für Typ • Beispiele: type IntPair = (Int,Int) curry :: (IntPair -> Int) -> Int -> Int -> Int type MaybeFloat = (Bool, Float) • Vordefiniert: type String = [Char] kanonische Rep.: "..." 23 Notation für Listen [n .. m] [n,n+1,...,m'] [2 .. 7] [2,3,4,5,6,7] [n,p .. m] [n,n+(n-p),...,m'] [7,5 .. 2] [7,5,3] 24 List-Comprehensions • Mathe: M = { f (x,y) | x ∈ A, y ∈ B} Idee: Aus bestehender Liste neue Liste erzeugen Beispiel: [3 * n | n <- [2,4,7,8,19], isEven n] => [6,12,24] 25 List-Comprehensions Operationen: • Generieren • Filtern Syntax: [ expr | qual1 , ... , qualN ] Qualifiers: • pattern <- expr Generator • expr Guard Variablen aus pattern sind in allen Ausdrücken "rechts" des Generators gebunden 26