Grundlagen der Programmierung 2 (1.C) Prof. Dr. Manfred Schmidt-Schauÿ Künstliche Intelligenz und Softwaretechnologie 3. Mai 2006 Funktionen auf Listen: map map :: (a -> b) -> [a] -> [b] map f [] = [] map f (x:xs) = (f x) : (map f xs) map wendet eine Funktion f auf alle Elemente einer Liste an konstruiert Liste der Ergebnisse. [] und (x:xs) links sind Muster(Pattern) Grundlagen der Programmierung 2 (1.C) - 1 - Funktionen auf Listen: Beispiele map f [] map f (x:xs) = [] = (f x) : (map f xs) map quadrat (1:(2:[])) quadrat 1 : map quadrat (2:[]) 1*1 : map quadrat (2:[]) 1 : map quadrat (2:[]) 1 : (quadrat 2 : map quadrat []) 1 : (2*2 : map quadrat []) 1 : (4 : map quadrat []) 1 : (4 : []) Grundlagen der Programmierung 2 (1.C) Zweite Gleichung [quadrat/f,1/x,(2:[])/xs] Interpreter will alles auswerten: deshalb Zweite Gleichung wg Interpreter Erste Gleichung = [1,4] - 2 - Auswertung: Wieviel ist nötig? istLeer [] = True istLeer (x:xs) = False zahlenAb n = n: zahlenAb (n+1) Auswertung istLeer [1..] istLeer (zahlenAb 1) istLeer (1: zahlenAb (1+1)) False Grundlagen der Programmierung 2 (1.C) verwende zahlenAb Zweite Gleichung von istLeer - 3 - Listenfunktionen und Listenerzeuger *Main> map quadrat [1..10] [1,4,9,16,25,36,49,64,81,100] *Main> map quadrat [1..] [1,4,9,16,25,36,49,64,81,100,121, .... Der Listenerzeuger [1..] erzeugt soviel von der Liste [1,2,3,4,5, usw. wie von der Listenfunktion benötigt wird. Grundlagen der Programmierung 2 (1.C) - 4 - Typen von Listenausdrücken mapQuadrat xs = map quadrat xs mapQuadrat :: forall a. (Num a) => [a] -> [a] mapLength xs = map length xs mapLength :: forall a. [[a]] -> [Int] Grundlagen der Programmierung 2 (1.C) - 5 - Listenfunktion append Die folgende Funktion hängt zwei Listen zusammen: append :: [a] -> [a] -> [a] append [] ys = ys append (x:xs) ys = x : (append xs ys) Haskell-Operator: ++ und Infix Haskell-Schreibweise: [1,2,3] ++ [4,5,6,7] Grundlagen der Programmierung 2 (1.C) - 6 - Beispiele Main> [] ++ [3,4,5] [3,4,5] Main> [0,1,2] ++ [] [0,1,2] Main> [0,1,2] ++ [3,4,5] [0,1,2,3,4,5] Main> [0..10000] ++ [10001..20000] == [0..20000] True Grundlagen der Programmierung 2 (1.C) - 7 - Funktionen auf Listen (2) Filtern von Elementen aus einer Liste: (a -> Bool) -> [a] -> [a] filter f [] = [] filter f (x:xs) = if (f x) then x : filter f xs else filter f xs Beispiele: filter (< 5) [1..10] [1,2,3,4] *Main> filter primzahlq [2..] [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71, 73,79,83,89,97,101,103,107,109,113,127,131,137,139, 149,151,157,163,167,173,179,181,191,193,197,199,211, Grundlagen der Programmierung 2 (1.C) - 8 - Funktionen auf Listen Die ersten n Elemente der Liste xs: take take take take :: Int -> [a] -> [a] 0 _ = [] n [] = [] n (x:xs) = x : (take (n-1) xs) *Main> take 10 [20..40] [20,21,22,23,24,25,26,27,28,29] *Main> take 10 [20,23..] [20,23,26,29,32,35,38,41,44,47] Grundlagen der Programmierung 2 (1.C) - 9 - Auswertungsreihenfolge, Definitionseinsetzung Auswertung von f s1 . . . sn wenn Muster verwendet wurden: Vor Definitionseinsetzung diejenigen Argumente auswerten, die für die Fallunterscheidung benötigt werden. Aber nur soviel wie nötig Zuordnung: Mustervariablen zu Ausdruck analog wie Zuordnung: formale Parameter zu Argumenten. Z.B. Muster (x:xs) und Argument (s :t) ergibt [s/x, t/xs] Grundlagen der Programmierung 2 (1.C) - 10 - Iterative Prozesse mit Listenargumenten Bei Verwendung von Listenargumenten: Die folgenden Begriffe sind unverändert: linear rekursiv, end-rekursiv, Baum-rekursiv verschachtelt Baum-rekursiv iterativ muss neu definiert werden. Grundlagen der Programmierung 2 (1.C) - 11 - Iterativer Auswertungsprozess zu f Ein iterativer Auswertungsprozess liegt vor, wenn (f a1 . . . an) → (3) (f a1 (3) → . . . an ) (j) und alle ai (f a01 . . . a0n) → sind ...... (2) → (f a1 → (f a1 (2) . . . an ) (m) (m) . . . an ) → ... Basiswerte oder komplett ausgewertete, endliche Listen Grundlagen der Programmierung 2 (1.C) - 12 - iterative Version fiter von f fiter ist iterative Version von f Wenn: f und fiter das gleiche berechnen und fiter einen iterativen Prozess erzeugt für alle Basiswerte und alle komplett ausgewerteten endlichen Listen als Eingaben Grundlagen der Programmierung 2 (1.C) - 13 - Listen: Auswertung Listenargumente nennt man: einfach ausgewertet: wenn Listen-Fallunterscheidung möglich ist, d.h. [] oder : ist Top-Konstruktor des Arguments Grundlagen der Programmierung 2 (1.C) - 14 - Beispiel: iterative Version von lengthr: length_lin xs = length_linr 0 xs length_linr s [] = s length_linr s (x:xs) = (length_linr (s+1) xs) lengthr [] = 0 lengthr (x:xs) = 1 + lengthr xs Grundlagen der Programmierung 2 (1.C) - 15 - Beispiel: iterativer Prozess Beachte: applikative Reihenfolge der Auswertung length_lin (9:(8:(7:(6:...(1:[]))))) length_linr 0 (9:(8:(7:(6:...(1:[]))))) length_linr 1 (8:(7:(6:...(1:[])))) length_linr 2 (7:(6:...(1:[]))) length_linr 3 (6:...(1:[])) .......... Grundlagen der Programmierung 2 (1.C) - 16 - Allgemeine Funktionen auf Listen Allgemeine Funktionen (Methoden): foldl und foldr Die 3 Argumente sind: • • • eine zweistellige Operation, ein Anfangselement (Einheitselement) und die Liste. foldl ⊗ e [a1, . . . , an] entspricht ((. . . ((e ⊗ a1) ⊗ a2) . . . ) ⊗ an). foldr ⊗ e [a1, . . . , an] entspricht a1 ⊗ (a2 ⊗ (. . . (an ⊗ e))) Grundlagen der Programmierung 2 (1.C) - 17 - Definitionen der fold-Funktionen foldl (Linksfaltung) foldr (Rechtsfaltung) foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z [] = z foldl f z (x:xs) = foldl f (f z x) xs foldr :: (a -> b -> b) -> b -> [a] -> b foldr f z [] = z foldr f z (x:xs) = f x (foldr f z xs) Grundlagen der Programmierung 2 (1.C) - 18 - Fold-Verwendungen Summe bzw. Produkt einer Liste von Zahlen: sum xs = foldl (+) 0 xs produkt xs = foldl (*) 1 xs concat xs = foldr (++) [] xs foldl (+) 0 [1,2,3,4] foldr (++) [] [[0],[2,3],[5]] ≡ ≡ ((((0+1)+2)+3)+4) [0] ++ ([2,3] ++ ([5] ++ [])) Je nach Operator is foldl, oder foldr besser geeignet. Grundlagen der Programmierung 2 (1.C) - 19 - Lokale Funktionsdefinitionen, anonyme Funktionen, Lambda-Ausdrücke Kann Funktionsnamen ersetzen Lambda-Ausdruck \x1 . . . xn -> hAusdrucki Die Notation \x -> ist Ersatz für die Church-Notation: λx. Beispiel quadrat = \x -> x*x Lokale Funktionsdefinition: Anonyme Funktion Lambda-Ausdruck an der Stelle von f Lambda-Ausdruck hat keine Namen Äquivalent sind: \x1 -> (\x2 -> ... (\xn -> t) ...) Grundlagen der Programmierung 2 (1.C) und \x1 x2 ... xn -> t. - 20 - let und lokale Bindungen let {x1 = s1; . . . ; xn = sn} in t {x1 = s1; . . . ; xn = sn} ist eine lokale Umgebung die Variablen xi können in t vorkommen mit der Bedeutung: Wert von si ” t der eigentliche Ausdruck In Haskell: rekursives let. D.h. xi kann in jedem sj vorkommen Beachte im ghci-Interpreter: Spezielle Verwendung des let Grundlagen der Programmierung 2 (1.C) - 21 - Erweiterungen des let Funktionen sind definierbar direkt in einem rekursiven let: let {f x1 . . . xn = s; . . .} in t ist das gleiche wie: let {f = \x1 . . . xn -> s; . . .} in t Grundlagen der Programmierung 2 (1.C) - 22 - Reduktionen von let-Ausdrücken nicht-rekursives let: let {x1 = s1; . . . ; xn = sn} in t t[s1/x1, . . . , sn/xn mit Sharing-Markierungen Wie man ein rekursives let weiter-reduzieren kann: let {x1 = s1; . . . ; xn = sn} in t let {x1 = s1σ; . . . ; xn = snσ} in tσ mit σ = [s1/x1, . . . , sn/xn] Grundlagen der Programmierung 2 (1.C) - 23 - Freie und Gebundene Variablen, Gültigkeitsbereiche Um Definitionen von lokalen Namen korrekt zu handhaben braucht man neue Begriffe: Gültigkeitsbereich einer Variablen x freie Variablen eines Ausdrucks gebundene Variablen eines Ausdrucks Text-Fragment(e) des Programms in dem dieses x gemeint ist. Variablen, deren Bedeutung außerhalb des Ausdrucks festgelegt wird. Variablen, deren Bedeutung innerhalb des Ausdrucks festgelegt wird. Problem: Variablen können mit gleichem Namen, aber verschiedener Bedeutung in einem Ausdruck vorkommen: Lösung: Exakte Festlegung der Gültigkeitsbereiche für jedes syntaktische Konstrukt Umbenennen von gebundenen Variablennamen, falls nötig Grundlagen der Programmierung 2 (1.C) - 24 - Beispiel \x-> x*x Gültigkeitsbereich von x: der Ausdruck x*x die Variable x ist gebunden von \x x*x in diesem Ausdruck ist x frei Grundlagen der Programmierung 2 (1.C) - 25 - Definition von FV FV: ergibt Menge von Variablen-Namen. • • • • • • F V (x) := {x} , wenn x ein Variablenname ist F V ((s t)) := F V (s) ∪ F V (t) F V (if t1 then t2 else t3) := F V (t1) ∪ F V (t2) ∪ F V (t3) F V (\x1 . . . xn -> t) := F V (t) \ {x1, . . . , xn} F V (let x1 = s1, . . . , xn = sn in t) := (F V (t) ∪ F V (s1) ∪ . . . ∪ F V (sn)) \ {x1, . . . , xn} F V (let f x1 . . . xn = s in t) := F V (let f = \x1 . . . xn -> s in t) Grundlagen der Programmierung 2 (1.C) - 26 - Beispiel: freie Variablen F V (\x -> (f x y)) Grundlagen der Programmierung 2 (1.C) = = = = F V (f x y ) \ {x} ... {x, f, y} \ {x} {f, y} - 27 - Gebundene Variablen GV (t) Entsprechend der F V -Definition: • • • • • • GV (x) := ∅ GV ((s t)) := GV (s) ∪ GV (t) GV (if t1 then t2 else t3) := GV (t1) ∪ GV (t2) ∪ GV (t3) GV (\x1 . . . xn -> t) := GV (t) ∪ {x1, . . . , xn} GV (let x1 = s1, . . . , xn = sn in t) := (GV (t) ∪ GV (s1) ∪ . . . ∪ GV (sn) ∪ {x1, . . . , xn}}) GV (let f x1 . . . xn = s in t) := GV (let f = \x1 . . . xn -> s in t) = {f, x1, . . . , xn} ∪ GV (s) ∪ GV (t) Grundlagen der Programmierung 2 (1.C) - 28 - Beispiel : Berechnung von gebundenen Variablen GV(\x -> (f x y)) Grundlagen der Programmierung 2 (1.C) = = = = GV (f x y) ∪ {x} ... ∅ ∪ {x} {x} - 29 - Lexikalischer Gültigkeitsbereich einer Variablen • let x = s • \x1 . . . xn -> t in t Grundlagen der Programmierung 2 (1.C) die Vorkommen der freien Variablen x in s, t werden gebunden. s, t ist der Gültigkeitsbereich der Variablen x die freien Variablen x1, . . . , xn in t werden gebunden. t ist der Gültigkeitsbereich der Variablen x1 , . . . , x n . - 30 - Beispiel Ausdruck t = \x -> (x (\x -> x*x)) x ist in t gebunden, aber in zwei Bindungsbereichen: \x -> (x (\x -> x*x)) In (x (\x -> x*x)) kommt x frei und gebunden vor. Umbenennen des gebundenen x in y ergibt: (x (\y -> y*y)) Grundlagen der Programmierung 2 (1.C) - 31 - Beispiele Zwei Bindungsbereiche für x in einem let-Ausdruck: let x = 10 in (let x = 100 in (x+x)) + x Umbenennung ergibt: let x1 = 10 in (let x2 = 100 in (x2+x2)) + x1 Dieser Term wertet zu 210 aus. Grundlagen der Programmierung 2 (1.C) - 32 - Beispiele Der Ausdruck let x = (x*x) in (x+x) führt zu Nichtterminierung. Grundlagen der Programmierung 2 (1.C) - 33 - Beispiel: Reihenfolgenunabhängigkeit der Bindungen let y = 20*z x = 10+y z = 15 in x Wertet aus zu : 310. Grundlagen der Programmierung 2 (1.C) - 34 - Beispiel geschachtelte Bindungsbereiche let {x = 1;y = 2} in (let {y = 2; z = 4} in (let z = 5 in (x+y+z))) x = 1; y = 2 y = 2; z = 4 z=5 (x+y+z) Grundlagen der Programmierung 2 (1.C) - 35 - Programm als let Ein Programm mit den Definitionen fi := ei | i = 1, . . . , n und dem auszuwertenden Ausdruck main kann als großes“ let betrachtet werden: ” let {f1 := e1; . . . ; fn := en} in main Grundlagen der Programmierung 2 (1.C) - 36 - Optimierung mittels let Vermeidung redundanter Auswertungen mit let f (x, y) := x(1 + xy)2 + y(1 − y) + (1 + xy)(1 − y) optimierbar durch Vermeidung von Doppelauswertungen: Der zugehörige Ausdruck ist: let a = 1 + x*y b = 1 - y in x*a*a + y*b + a*b Grundlagen der Programmierung 2 (1.C) - 37 - Allgemeine Methoden: Funktionen als Argumente Funktionen höherer Ordnung Beispiele für (arithmetische) Aufgabenstellungen: Nullstellenbestimmung, Integrieren, Differenzieren, Ermitteln von Maxima, Minima von Funktionen . . . Grundlagen der Programmierung 2 (1.C) - 38 - Nullstellenbestimmung einer stetigen Funktion mit Intervallhalbierung Sei f stetig und f (a) < 0 < f (b), m = (a + b)/2 f a (a+b)/2 b • wenn f (m) > 0, dann Nullstelle in [a, m]. • wenn f (m) < 0, dann Nullstelle in [m, b]. Grundlagen der Programmierung 2 (1.C) - 39 - Nullstellenbestimmung: Programm (1) Parameter: • • • • Name der arithmetischen (Haskell-) Funktion Intervall-Anfang Intervall-Ende Genauigkeit der Nullstelle (absolut). suche_nullstelle:: (Double->Double) -> Double -> Double -> Double -> Double suche_nullstelle f a b genau = ... (siehe Programmfile) Grundlagen der Programmierung 2 (1.C) - 40 - Nullstellenbestimmung: Programm (3) *Main> suche_nullstelle cos 0 3 0.000000000000001 1.5707963267948966 *Main> 1.5707963267948966/pi 0.5 *Main> pi/2 1.5707963267948966 *Main> Grundlagen der Programmierung 2 (1.C) - 41 - Intervallhalbierungsmethode: Komplexität maximale Anzahl der Schritte: dlog2(L/G)e, wobei L G Länge des Intervalls Genauigkeit Zeitbedarf: Platzbedarf: O(log(L/G)) O(1) Grundlagen der Programmierung 2 (1.C) - 42 - Funktionen als Ergebnis Beispiel: Komposition von Funktionen: komp::(a -> b) -> (c -> a) -> c -> b komp f g x = f (g x) *Main> suche_nullstelle (sin ‘komp‘ quadrat) 1 4 0.00000001 1.772453852929175 (sin ‘komp‘ quadrat) entspricht sin(x2) und quadrat ‘komp‘ sin entspricht (sin(x))2. Grundlagen der Programmierung 2 (1.C) - 43 - Typ der Komposition Erklärung zum Typ von komp, wobei {a,b,c} Typvariablen sind Ausdruck: f1 ‘komp‘ f2 bzw. f1 . f2 (a->b) -> (c->a) -> c->b (a->b) (c->a) c b Typ von komp Typ von f1 Typ von f2 Typ des Arguments x der Komposition f1 . f2 Typ des Resultats der Komposition f1(f2 x) f1 ‘komp‘ f2:: c -> b. Grundlagen der Programmierung 2 (1.C) - 44 - Beispiel: näherungsweises Differenzieren x Df (x) := x+∆x f (x + dx) − f (x) dx ableitung f dx = \x -> ((f(x+dx)) - (f x)) / dx Resultat: Funktion, die die Ableitung f 0 annähert *Main> ((ableitung (\x -> x^3) 0.00001) 5) 75.00014999664018 ---- korrekter Wert: 3*5^2 = 75 Grundlagen der Programmierung 2 (1.C) - 45 - Variante der Newtonschen Methode zur Bestimmung der Nullstellen y2 Vorgehen: y1 Ersetze Schätzwert y1 durch f (y1) verbesserten Schätzwert y2 = y1 − . Df (y1) Grundlagen der Programmierung 2 (1.C) - 46 - Variante der Newtonschen Methode zur Bestimmung der Nullstellen (2) newton_nst :: (Double -> Double) -> Double -> Double newton_nst f y = if (abs (f y)) < 0.0000000001 then y else newton_nst f (newton_nst_verbessern y f) newton_nst_verbessern y f = y - (f y) / (ableitung f 0.00001 y) Beispiel: Nullstelle der Funktion x2 − x mit Startwert 4. *Main> newton_nst (\x -> x^2-x) 4 1.0000000000001112 Grundlagen der Programmierung 2 (1.C) - 47 - Datentypen in Haskell Basisdatentypen • • • • • • Ganze Zahlen (Int) Unbeschränkte ganze Zahlen (Integer). Rationale Zahlen. Komplexe Zahlen (im Haskell-Module Complex). Gleitkommazahlen (Gleitpunktzahlen) (Float). z.B. 1.234 e-40 Zeichen, Character. i.a. ASCII-Zeichen zu 1 Byte bzw. Unicode Grundlagen der Programmierung 2 (1.C) - 48 - Zusammengesetzte Daten-Objekte Paar: Beispiele (x, y) (1, 2) (1, "hallo") (1,(2,"hallo")) Grundlagen der Programmierung 2 (1.C) - 49 - Anwendungs-Beispiel: Rationale Zahlen Repräsentation als Paar: (Zähler, Nenner) Beachte: in Haskell vordefiniert x in Haskell als x%y gedruckt. y Beispiele: Prelude> (3%4)*(4%5) 3 % 5 Prelude> 1%2+2%3 7 % 6 Datenkonversionen: Grundlagen der Programmierung 2 (1.C) z.B. toRational, truncate. - 50 - n-Tupel von Objekten Als Verallgemeinerung von Paaren (t1, . . . , tn) ist n-Tupel von t1, . . . , tn Beispiele (1,2,3,True) (1,(2,True),3) ("hallo",False) (fakultaet 100,\x-> x) Grundlagen der Programmierung 2 (1.C) - 51 - Zusammengesetzte Objekte: Datentypen Für Datentypen benötigt man: Datenkonstruktor(en) Datenselektor(en) Beispiel Paarkonstruktor Paarselektoren s, t −→ (s, t) fst, snd Eigenschaften: fst(s, t) = s und snd(s, t) = t. Grundlagen der Programmierung 2 (1.C) - 52 - Beispiel n-Tupel n-Tupelkonstruktor t1, . . . , tn −→ (t1, . . . , tn) Tupelselektoren n Selektoren: pro Stelle ein Selektor n-Tupel haben einen impliziten Konstruktor: (., . . . , .) | {z } n Grundlagen der Programmierung 2 (1.C) - 53 - Definition der Selektoren Muster (pattern) statt Selektoren. Muster sind syntaktisch dort erlaubt, wo formale Parameter (Variablen) neu eingeführt werden: • • • in Funktionsdefinitionen, in Lambda-Ausdrücken und in let-Ausdrücken. Beispiel-Definitionen von Selektoren mittels Muster fst (x,y) = x snd (x,y) = y selektiere_erstes_von_3 (x1,x2,x3) = x1 selektiere_zweites_von_3 (x1,x2,x3) = x2 selektiere_drittes_von_3 (x1,x2,x3) = x3 Grundlagen der Programmierung 2 (1.C) - 54 - Beispiel: Typen von Selektoren, Konstruktoren, Tupeln (1, 1) :: (Integer, Integer) (1, (2, True)) :: (Integer, (Integer, Bool)) (., . . . , .) :: α1 → α2 → . . . → αn → (α1, α2, . . . , αn) :: (α1, α2, α3) → α3 | {z } n selektiere_drittes_von_3 Grundlagen der Programmierung 2 (1.C) - 55 - Benutzerdefinierte Konstruktoren In Haskell mittels data-Anweisung Beispiel data Punkt = Punktkonstruktor Double Double data Strecke = Streckenkonstruktor Punkt Punkt data Viertupel a b c d = Viertupelkons a b c d Grundlagen der Programmierung 2 (1.C) - 56 - Muster (pattern) Nutzen der Muster: Gleichzeitiges und tiefes Selektieren Ersatz für Selektoren Syntax der Muster: hMusteri ::= hVariablei | (hMusteri) | hKonstruktor(n)i hMusteri . . . hMusteri | {z n } | (hMusteri, . . . , hMusteri) Kontextbedingung: in einem Muster keine Variable doppelt Grundlagen der Programmierung 2 (1.C) - 57 - Auswertung unter Benutzung von Mustern Mustervergleich: Anpassen des Objekts an das Muster gleichzeitige Selektion mittels impliziter let-Bindungen I.a. vorher Auswertung des Objekts erforderlich Beispiele (x,y,(u,v)) anpassen an: (1,2,(3,4)) ergibt: let {x = 1;y = 2;u = 3;v = 4} in ... (x,y,(u,v)) anpassen an: (1,2,True) ergibt: Fehler. Kann nicht vorkommen wegen Typcheck. (x,y,u) anpassen an: (1,2,(4,5)) ergibt: let {x = 1; y = 2;u = (4,5)} Grundlagen der Programmierung 2 (1.C) in ... - 58 - Auswertung unter Benutzung von Mustern (2) Beispiele (x,y) anpassen an: (1,fakt 100) ergibt: {let {x = 1; y = fakt 100} in ... (x,y) anpassen an: (fst (1,2), snd (fakt 100,fakt 200)) ergibt : let {x = fst (1,2); y = snd (fakt 100, fakt 200)} in ... Grundlagen der Programmierung 2 (1.C) - 59 - Benutzerdefinierte Typnamen mit Parametern Beispiel Punkt, Strecke, Polygonzug data data data data Punkt a Strecke a Vektor a Polygon a = = = = Punkt a a Strecke (Punkt a) (Punkt a) Vektor a a Polygon [Punkt a] Typ und Konstruktor können gleiche Namen haben. Der Parameter a kann jeder Typ sein: z.B.: Float, Int, aber auch [[(Int, Char)]] Grundlagen der Programmierung 2 (1.C) - 60 - Funktionen auf Punkt, Strecke, Polygonzug addiereVektoren::Num a => Vektor a -> Vektor a -> Vektor a addiereVektoren (Vektor a1 a2) (Vektor b1 b2) = Vektor (a1 + b1) (a2 + b2) streckenLaenge (Strecke (Punkt a1 a2) (Punkt b1 b2)) = sqrt (fromInteger ((quadrat (a1 - b1)) + (quadrat (a2-b2)))) Grundlagen der Programmierung 2 (1.C) - 61 - Summentypen und Fallunterscheidung Summentyp: diese haben mehr als einen Konstruktor Beispiele: Bool mit True False data Wahrheitswerte = Wahr | Falsch Aufzählungstyp: data Farben = Rot | Gruen | Blau | Weiss | Schwarz data Kontostand = Dm (Integer) | Euro (Integer) | Dollar (Integer) | SFranken (Integer) Grundlagen der Programmierung 2 (1.C) - 62 - Funktionsdefinition mit mehreren Mustern: Beispiele: und1 und1 und1 und1 Wahr Falsch Wahr Wahr Falsch Falsch Falsch Wahr = = = = Falsch Wahr Falsch Falsch oder und2 und2 Wahr x Falsch x = x = Falsch Wahr x Falsch _ = x = Falsch oder und3 und3 Grundlagen der Programmierung 2 (1.C) -- Joker, Wildcard - 63 - Fallunterscheidung mit case Syntax: case hAusdrucki of {h Musteri -> hAusdrucki; . . . ;hMusteri -> hAusdrucki} Einschränkung: Kontextbedingung: nur einfache Muster: K x1 . . . xn die Muster müssen vom Typ her passen. Beispiel: und4 x y = case x of True -> y; False -> False Grundlagen der Programmierung 2 (1.C) - 64 - case: Gültigkeitsbereich, FV und GV F V (case s of (c1 x11 . . . x1n1 → t1); . . . ; (ck xk1 . . . xknk → tk )) = F V (s) ∪ F V (t1) \ {x11, . . . x1n1 } . . . ∪ F V (tk ) \ {xk1, . . . xknk } GV(.) entsprechend Grundlagen der Programmierung 2 (1.C) - 65 - case: Gültigkeitsbereich, Beispiel F V (case x of True -> y; False -> False) = {x,y} F V (case x of (Punkt u v) -> u) = {x } GV (case x of (Punkt u v) -> u) = {u,v} Grundlagen der Programmierung 2 (1.C) - 66 -