Ganzzahlen beschränkter Länge Überladung Beobachtungen: Der Typ Int umfasst Ganzzahlen beschränkter Länge • Alle Zahlenoperatoren und Funktionen arbeiten auf Int und Integer. Operatoren: +,*,^,• == und /= arbeiten auf Bool, Int und Integer (und vielen mehr) Funktionen: div, mod, abs, negate Vergleichsoperatoren: >,>=,==,/=,<=,< Überladung: Der gleiche Name wird für verschiedene Operationen verwendet. Auf den Folien jetzt immer Int. Auch die Zahlenkonstanten sind überladen Später: Überladung selbst definieren Guards Syntax und Auswertung von Guards Syntax: name pat+ | guard-expr = expr 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 • 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. 1-4 Zeichen Fließkommazahlen • Typ: Float • Typ: Char • Literale: 0.235, 231.61e7, -2.33 • Literale: Zeichen zwischen Hochkommata, z.B. 'a', '3' • Eingebaute Funktionen: Arithmetik, Trigonometrie, ... • Spezailfälle: '\t', '\n','\\','\'','\"' • Funktionen, Operatoren und Konstanten sind überladen. 1.0 + 2.2 = 3.2 abs -2.2 = 2.2 round 1 = 1 • Modul Char stellt einige Funktionen für Zeichen bereit Typkonversion für Zahlen Layout-Syntax • Das Layout (die Einrückung) eines Haskell-Programms bestimmt die Syntax. • Bei Definitionen: Automatische Typkonversion findet nicht statt! Erster Buchstabe beginnt Definition • 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 Buchstabe mit gleicher Einrückung beendet Definition foo x = x + x - 3 g y = y 5-8 Layout-Syntax Konstruktion von Funktionen • Explizites Ende mit ; möglich Zuerst: • Bei Guards bestimmen | und = die Syntax: threeMax x y z | x >= y && x >= z = x | y >= z = y | otherwise 1. Kurze Beschreibung als Kommentar 2. Typsignatur angeben 3. Beispiele angeben In Zukunft immer bei den Abgaben! = z Konstruktion rekursiver Funktionen über Zahlen Schablone für primitiv-rekurisive Funktionen • 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. f n | n == 0 = ... | n > 0 = ... f (n - 1) ... D.h. annehmen, dass f (n - 1) bereits die Spezifikation erfüllt. 9-12 Konstruktion allgemein rekursiver Funktionen über Zahlen Fehlermeldung ausgeben Schablone: f n | n == 0 = ... | n > 0 = ... f k ... Dabei annehmen, dass f k bereits die Spezifikation erfüllt. fac fac | | | :: Int -> Int n n == 0 = 1 n > 0 = n * fac (n - 1) * n otherwise = error "fac mit negativem Argument" Achtung: Terminierung ist hier nicht garantiert! Beispiele als Testfälle Tupel und Listen • 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 • Bis jetzt: Nur Basistypen Bei Guards alle Fälle abdecken • Jetzt: Zusammengesetzte Typen Beispiele sind ebenfalls Testfälle, am besten als White-Box-Tests formulieren three x = 3 testThree = Tupel: Feste Anzahl von Werten unterschiedlichen Typs Listen: Beliebige Anzahl von Werten gleichen Typs three 23 == 3 && three 34 == 3 13-16 Tupel Beispiele • 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) origin :: (Int,Int) origin = (0,0) makePoint :: Int -> Int -> (Int,Int) makePoint x y = (x,y) (1.2,'a',) :: (Float,Char,Int) • Die Syntax für Typen und Werte ist also gleich Muster für Tupel Nochmal Currying 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) • 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 17-20 Einschub: Aussagen über Programmen beweisen Listen • Beliebige Anzahl von Werten gleichen Typs • Funktionen sind als Gleichungen formuliert • Für jeden Typ t gibt es einen Typ [t] von Listen über t • Diese Gleichungen können auch in Beweisen verwendet werden • Freie Variabeln der Aussagen sind ∀-quantifiziert • Kanonische Repräsentation: [x,y,...] • Die leere Liste: [] Z.Z: square x ≡ x square x 2 • Beispiele: Def. Potenzieren Def.* Def.square 2 = x = x * x = x⋅x [1,2] :: [Int] ['a','b','c'] :: [Char] Einschub: Typsynonyme Notation für Listen • Auch für Typen können Namen definiert werden • Syntax: type name = Typ • Definiert name als Typsynonym für Typ [n .. m] [n,n+1,...,m'] • Beispiele: [2 .. 7] [2,3,4,5,6,7] type IntPair = (Int,Int) curry :: (IntPair -> Int) -> Int -> Int -> Int [n,p .. m] [n,n+(n-p),...,m'] [7,5 .. 2] [7,5,3] type MaybeFloat = (Bool, Float) • Vordefiniert: type String = [Char] kanonische Rep.: "..." 21-24 List-Comprehensions List-Comprehensions Operationen: • Generieren • Mathe: M = { f (x,y) | x ∈ A, y ∈ B} • Filtern Idee: Aus bestehender Liste neue Liste erzeugen Syntax: [ expr | qual1 , ... , qualN ] Beispiel: Qualifiers: [3 * n | n <- [2,4,7,8,19], isEven n] => [6,12,24] • pattern <- expr Generator • expr Guard Variablen aus pattern sind in allen Ausdrücken "rechts" des Generators gebunden 25-26