Listen und Funktionen auf Listen Achtung Zunächst: Einfache Einführung von Listen Listenfunktionen zugehörige Auswertung Genauere Erklärungen zu Listenfunktionen folgen noch (in ca, 1-2 Wochen) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 1 Listen und Listenfunktionen Listen modellieren Folgen von gleichartigen, gleichgetypten Objekten. [0,1,2,3,4,5,6,7,8,9] [] [’a’, ’b’, ’c’] [[], [0], [1, 2]] [1..] P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, Typ: [Integer]; d.h. Liste von Integer. leere Liste, (Nil) Typ: [Char]; abgekürzt als String Druckbild: "abc" Liste von Listen; Typ [[Integer]], d.h. eine Liste von Listen von Integer-Objekten. potentiell unendliche Liste [1,2,3,...] (8. Dezember2004) Seite 2 Listen und Listenfunktionen zwei Schreibweisen für Listen: [0, 1, 2] schöne Darstellung Druckbild einer Liste (0 : (1 : (2 : []))) interne Darstellung mit zweistelligem Infix-Listen-Konstruktor : “ ” und dem Konstruktor [] Eingebaute, listenerzeugende Funktionen: [n..] [n..m] [1..10] [n,m..k] P raktische Inf ormatik erzeugt die Liste der Zahlen ab n. erzeugt die Liste von n bis m ergibt [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] erzeugt die Liste von n bis k mit Schritten m − n 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 3 Darstellung von Listen Listen sind aufgebaut mittels zwei Konstruktoren: [] : Konstante für die leere Liste Zweistelliger Infix-Konstruktor Linkes Argument: erstes Element der Liste Rechtes Argument: Restliste Beispiel für Haskells Listenerzeugung: 8:[] 9:(8:[]) 10:(9:(8:[])) P raktische Inf ormatik 1, W S Liste [8] mit dem Element 8 Liste [9.8] mit zwei Elementen 8,9 Liste [10,9,8] mit drei Elementen 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 4 Baum-Bild einer Liste zz zz z zz z} z : @@@ 10 @@ @@ @@ 9 : <<< << << < 8 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 5 : ;;; ;; ;; ; [] Einfache Listenfunktionen Definitionen head (x:xs) tail (x:xs) = x = xs --Erstes Element --Restliste Auswertungen Prelude> head [] *** Exception: Prelude.head: empty list Prelude> head [1] ##intern: (1 : []) 1 Prelude> tail [] *** Exception: Prelude.tail: empty list Prelude> tail [1] [] Prelude> P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 6 Funktionen auf Listen: lengthr Länge einer Liste: lengthr [] = 0 lengthr (x:xs) = 1 + (lengthr xs) [] und (x:xs) in der Position von formalen Parametern nennt man Muster(Pattern) Zwei Fälle in den Definitionen: 1. Leere Liste oder 2. nicht-leere Liste. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 7 Beispiel lengthr lengthr [] = 0 lengthr (x:xs) = 1 + (lengthr xs) Auswertung lengthr (10:(9:(8:[]))) 1+ (lengthr (9:(8:[]))) 1+(1+ (lengthr (8:[]))) 1+(1+ (1+ (lengthr []))) 1+(1+ (1+ (0))) 3 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, Zweiter Fall; [10/x,(9:(8:[]))/xs] Zweiter Fall; [9/x, (8:[])/xs] Zweiter Fall; [8/x, ([])/xs] Erster Fall; 3 × Addition (8. Dezember2004) Seite 8 Funktionen auf Listen: map 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) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 9 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 : []) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Zweite Gleichung [quadrat/f,1/x,(2:[])/xs] Interpreter will alles auswerten: deshalb Zweite Gleichung wg Interpreter Erste Gleichung = [1,4] Seite 10 Listenerzeugende Funktionen [n..] [n..m] [1..10] [n,m..k] P raktische Inf ormatik erzeugt die Liste der Zahlen ab n. erzeugt die Liste von n bis m ergibt [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] erzeugt die Liste von n bis k mit Schritten m − n 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 11 Listenerzeugende Funktionen: Beispiel [n..m] fromTo n m = if n <= m then n : (fromTo (n+1) m) else [] [1..10] fromTo 1 10 if 1 <= 10 then ... if True then ... 1: (fromTo (1+1) 10) 1: (if (1+1) <= 10 then ... ) 1: (if 2 <= 10 then ... ) 1: (if True then ... ) 1: (2:(fromTo (2+1) 10) ) .... 1:(2:(3: ...(10:[] ) ... )) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Benutze fromTo Definitionseinsetzung wg. Eingabe in den Interpreter Seite 12 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 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, verwende zahlenAb Zweite Gleichung von istLeer (8. Dezember2004) Seite 13 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. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 14 Beispiel map quadrat [1..] map quadrat (zahlenAb 1) map quadrat (1:zahlenAb (1+1)) quadrat 1 : map quadrat (zahlenAb (1+1)) 1*1 : map quadrat (zahlenAb (1+1)) 1 : map quadrat (zahlenAb (1+1)) 1 : map quadrat ((1+1): zahlenAb ((1+1)+1)) 1 : (quadrat (1+1) : map zahlenAb ((1+1)+1)) 1 : (quadrat 2 : map zahlenAb (2+1)) 1 : (2*2 : map zahlenAb (2+1)) 1 : (4 : map zahlenAb (2+1)) ..... P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 15 verwende zahlenAb Auswertung zahlenAb 1 Muster in map passt wg. Interpreter verzögerte Red. Listenfunktion append Die folgende Funktion hängt zwei Listen zusammen: append [] ys append (x:xs) ys = ys = x : (append xs ys) In Haskell: ++ und Infix P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 16 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 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 17 Funktionen auf Listen (2) Filtern von Elementen aus einer Liste: filter f [] filter f (x:xs) = [] = if (f x) then x : filter f xs else filter f xs Die ersten n Elemente der Liste xs: take 0 _ = [] take n [] = [] take n (x:xs) = x : (take (n-1) xs) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 18 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] P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 19 Beispiele zu take repeat x = x : repeat x Auswertung: take 10 (repeat 1) take 10 (1:repeat 1) 1:(take (10-1) (repeat 1)) -- (x:xs) = (1:(repeat 1)) 1:(take 9 (repeat 1)) 1:(take 9 (1:(repeat 1))) 1:(1:(take (9-1) (repeat 1)) ... 1:(1: ... 1:(take (1-1) (repeat 1)) 1:(1: ... 1:(take 0 (repeat 1)) -- n = 0 1:(1: ... 1:[]) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 20 Beispiele zu filter und take filter (< 5) [1..10] [1,2,3,4] *Main> let ptest x = ist_primzahl_ft_naiv x && (not (primzahlq x)) *Main> filter ptest [2..] [561,1105,1729,2465,2821,6601 *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] P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 21 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. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 22 Iterativer Auswertungsprozess zu f Ein iterativer Auswertungsprozess liegt vor, wenn (f a1 . . . an) → (3) (f a1 (3) . . . an ) (j) und alle ai P raktische Inf ormatik → 1, W S sind (f a01 . . . a0n) → ...... (2) → (f a1 → (f a1 (2) . . . an ) (m) (m) . . . an ) Basiswerte oder komplett ausgewertete, endliche Listen 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 23 → ... 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 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 24 Applikativ, Strikt Listenargumente nennt man: einfach ausgewertet: wenn Listen-Fallunterscheidung möglich ist, d.h. [] oder : ist Top-Konstruktor des Arguments Funktion ist applikativ: wenn sie zuerst ihre Argumente auswertet. Funktion ist strikt: wenn sie ihre Argumente (irgendwann) auswertet. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 25 Beispiel: iterative Version von lengthr: length_lin xs length_linr s [] length_linr s (x:xs) length_linr_app s xs = = = = length_linr 0 xs s (length_linr_app (s+1) xs)) strikt_1 s (length_linr s xs) lengthr [] = 0 lengthr (x:xs) = 1 + lengthr xs P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 26 Beispiel: iterativer Prozess Beachte: length linr ist applikativ 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:[])) .......... P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 27 Allgemeine Funktionen auf Listen Allgemeine Funktionen (Methoden): foldl und foldr Die 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))) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 28 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]] entspricht entspricht Mal ist foldl, mal foldr besser geeignet. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 29 ((((0+1)+2)+3)+4) [0] ++ ([2,3] ++ ([5] ++ [])) Lokale Funktionsdefinitionen, anonyme Funktion, Lambda-Ausdrücke Statt Funktion mit Namen auf der Programmebene: Lambda-Ausdruck \x1 . . . xn -> hAusdrucki Die Notation \x -> ist Ersatz für die Church-Notation: λx. Beispiel äquivalente Definition von quadrat. 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) ...) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 30 und \x1 x2 ... xn -> t. 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 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 31 Beispiel let-Reduktion let fakt = \x -> if x <= 1 then 1 else x*(fakt (x-1)) in fakt Auswertung der Anwendung von fakt auf 5 ergibt: (Die Reduktionsregeln kommen später nochmal) (Hier etwas vereinfacht) (let fakt = \x -> if x <= 1 then 1 else x*(fakt (x-1)) in fakt) 5 -> let fakt = ... in (fakt 5) -> let fakt = ... in if 5 <= 1 then 1 else 5*(fakt (5-1)) -> let fakt = ... in if False then 1 else 5*(fakt (5-1)) -> let fakt = ... in 5*(fakt (5-1)) .... ergibt: 120. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 32 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 (let fakt = \x -> if x <= 1 then 1 else x*(fakt (x-1)) in fakt ist äquivalent zu (let fakt x = if x <= 1 then 1 else x*(fakt (x-1)) in fakt P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 33 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: P raktische Inf ormatik Exakte Festlegung der Gültigkeitsbereiche für jedes syntaktische Konstrukt Umbenennen von gebundenen Variablennamen, falls nötig 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 34 Beispiel \x-> x*x Gültigkeitsbereich von x: der Ausdruck x*x die Variable x ist gebunden von \x x*x P raktische Inf ormatik in diesem Ausdruck ist x frei 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 35 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) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 36 Beispiel: freie Variablen F V (\x -> (f x y)) P raktische Inf ormatik 1, W S = = = = 2004/05, F olien Haskell−3, F V (f x y ) \ {x} ... {x, f, y} \ {x} {f, y} (8. Dezember2004) Seite 37 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) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 38 Beispiel : Berechnung von gebundenen Variablen GV(\x -> P raktische Inf ormatik 1, W S (f x y)) 2004/05, F olien Haskell−3, = = = = GV (f x ... ∅ ∪ {x} {x} (8. Dezember2004) Seite 39 y) ∪ {x} Lexikalischer Gültigkeitsbereich einer Variablen • let x = s • \x1 . . . xn -> t P raktische Inf ormatik 1, W S in t 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 . 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 40 Beispiel Ausdruck t = \x -> (x (\x -> x*x)) x ist in t gebunden, aber in zwei Gültigkeitsbereichen (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)) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 41 Beispiele Zwei Gültigkeitsbereiche 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. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 42 Beispiele Der Ausdruck let x = (x*x) in (x+x) führt zu Nichtterminierung. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 43 Beispiel: Reihenfolgenunabhängigkeit der Bindungen let y = 20*z x = 10+y z = 15 in x Wertet aus zu : 310. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 44 Beispiel geschachtelte Bindungsbereiche let {x = 1;y = 2} in (let {y =3; z = 4} in (let z = 5 in (x+y+z))) x = 1; y = 2 y = 2; z = 4 z=5 (x+y+z) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 45 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 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 46 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 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 47 Reduktion von let-Ausdrücken Wünsche an die Transformationsregeln: • operationale Semantik für Let und Lambda • können verzögerte Auswertung modellieren • machen implizite Gleichheitsmarkierung explizit • vermeiden Doppelauswertung P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 48 Reduktion von let-Ausdrücken Plan: Mehrere Reduktionsregeln für Ausdrücke mit let Vollständige Angabe aller Regeln Verallgemeinerung des Begriffs Basiswert: WHNF als Ende einer Auswertung P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 49 Auswertungsregeln bei let und Lambda Definitionseinsetzung mit let (f t1 . . . tn) → (let {x1 = t1; . . . ; xn = tn} in Rumpf0f ) Bedingungen: Die Definition von f ist: f x1 . . . xn = Rumpf f Rumpf 0f ist eine Kopie von Rumpf f , in der gebundene Variablen umbenannt sind. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 50 Auswertungsregel Beta entsprechend der Definitionseinsetzung mit let: Beta-Reduktion (mit let) ((\ x1 . . . xn -> e) t1 . . . tn) → (let {x1 = t1; . . . ; xn = tn} in e) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 51 Beispiel (\x -> x*x) 2 let x = 2 in x*x Es fehlen noch Regeln! P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 52 Reduktion von let-Ausdrücken Let-Kopier-Regel(n) let {x = s; E nv} in e[x]p → let {x = s; E nv} in e[s0]p let {x = s; y = e[x]p; E nv} in r → let {x = s; y = e[s0]p; E nv} in r Wenn s Basiswert,oder Abstraktion, oder f t1 . . . tn mit n < ar(f ). s0 ist s nach Umbenennung der gebundenen Variablen. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 53 Kopieren von Konstruktorausdrücken Let-Kopier-Regel(n) let {x = c t1 . . . tn; E nv} in e[x]p → let {x = c x1 . . . xn; x1 = t1; . . . ; xn = tn; E nv} in e[c x1 . . . xn]p let {x = c t1 . . . tn; y = e[x]p; E nv} in r → let {x = c x1 . . . xn; x1 = t1; . . . ; xn = tn; y = e[c x1 . . . xn]p; E nv} in r Wenn c Konstruktor mit n = ar(c) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 54 Beispiel (\x -> x*x) 2 let let let let x x x x = = = = 2 2 2 2 in in in in x*x 2*x 2*2 4 Es fehlen immer noch Regeln! P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 55 Speicher-Bereinigung (garbage collection) Let-Speicher-Bereinigung-1 let {x1 = s1; . . . ; xn = sn} in e −→ e wenn e kein freies Vorkommen der Variablen xi für i = 1, . . . , n hat. Let-Speicher-Bereinigung-2 let {x1 = s1; . . . ; xn = sn; xn+1 = sn+1; . . .} in e → let {xn+1 = sn+1; . . .} in e wenn xi für i = 1, . . . , n weder in e noch in einem sj mit j ≥ n + 1 frei vorkommt. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 56 Beispiel (\x -> x*x) 2 let let let let 4 x x x x = = = = 2 2 2 2 in in in in P raktische Inf ormatik 1, W S x*x 2*x 2*2 4 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 57 Umbenennung von gebundenen Variablen \x1 . . . xn -> e −→ \y1 . . . yn -> e[y1/x1, . . . , yn/xn] wenn yi neue Variablennamen sind. e[y1/x1, . . . , yn/xn]: alle freien Vorkommen von xi werden jeweils durch yi ersetzt Umbenennung aller gebundenen Variablen eines Ausdrucks: erfordert rekursives Vorgehen in allen Unterausdrücken Umbenennung geht analog für Let-Ausdrücke. Beachte, dass freie Variablen eines Ausdrucks nicht umbenannt werden. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 58 Ein komplexeres Beispiel \x -> (\y -> x ∗ ((\x -> x + y) 5)) Umbenennung: z.B. inneres x durch z ersetzen \x -> (\y -> x ∗ ((\z -> z + y) 5)). Verboten: Umbenennung von y in x. Sogenanntes Einfangen von Variablen Dies würde ergeben: \x -> (\x -> x ∗ ((\x -> x + x) 5)). Eine Variable würde dadurch ihre Zuordnung ändern P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 59 Ein komplexeres Beispiel (2) Eine korrekte Umbenennung des äußeren x ergibt: \z -> (\y -> z ∗ ((\x -> x + y) 5)). Dies kann man auch testweise in Haskell eingeben; man erhält für den falschen Ausdruck auch andere Ergebnisse. > (\x -> (\y -> x*((\x -> x+y) 5))) 2 2 14 > (\x -> (\x -> x*((\x -> x+x) 5))) 2 2 20 > (\z -> (\y -> z*((\x -> x+y) 5))) 2 2 14 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 60 Let-Verschieben Let-Anwendung-Verschieben ((let {x1 = t1; . . . ; xn = tn} in t) s) → (let {x1 = t1; . . . ; xn = tn} in (t s)) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 61 Beispiel ((\x -> (\y -> x*((\z -> z+y) 5))) 2) 2 (let x = 2 in (\y -> x*((\z -> z+y) 5))) 2 (let x = 2 in ((\y -> x*((\z -> z+y) 5)) 2) (let x = 2 in (let y = 2 in x*((\z -> z+y) 5))) (let x = 2 in (let y = 2 in 2*((\z -> z+y) 5))) (let y = 2 in 2*((\z -> z+y) 5)) (let y = 2 in 2*(let z = 5 in z+y)) (let y = 2 in 2*(let z = 5 in 5+y)) (let y = 2 in 2*(5+y)) (let y = 2 in 2*(5+2)) 2*(5+2)) 2*7 14 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8th December2004) Seite 62 Let-Glätten Let-Glätten-1 (let {x1 = t1; . . . ; xj = (let {y1 = r1; . . . ; ym = rm} in tj ); . . . ; xn = tn} in t) −→ (let {x1 = t1; . . . ; xn = tn; y1 = r1; . . . ; ym = rm} in t) Eine weitere Regel dazu: Let-Glätten-2 (let {x1 = t1; . . . ; xn = tn} in (let y1 = r1; . . . ; ym = rm in t)) −→ (let {x1 = t1; . . . ; xn = tn; y1 = r1; . . . ; ym = rm} in t) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 63 Schwache Kopfnormalform (weak head normal form, WHNF) ist eine Verallgemeinerung von Basiswert eine WHNF wird nicht weiter ausgewertet, kann aber unausgewertet Unterausdrücke enthalten schwache Kopfnormalform (WHNF): 1. 2. 3. 4. 5. Zahl oder Boolesch oder Zeichen, d.h. Basiswert Lambda-Ausdruck c t1 . . . tn und c ist ein Konstruktor und ar(c) = n f t1 . . . tn und f ist ein Funktionsname ist mit ar(f) > n (let{x1 = s1; . . . ; xn = sn} in t) und t ist von der Form 1–4 Zu Konstruktoren beachte: Im Moment ist nur : eingeführt und Konstanten. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 64 Normale (Verzögerte) Reihenfolge der Auswertung Die Definition ist zu umfangreich, deshalb nur Die Prinzipien und einige Regeln: • • • • • nur das notwendigste wird ausgewertet Glätte äußere let-Umgebung, falls notwendig Verfolge Bindungen wenn nötig und werte an Ort und Stelle aus Kopiere Ausdruck, wenn erforderlich let . . . in t: werte t aus Wenn WHNF erreicht wird, dann stoppe erfolgreich P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 65 Beispiel: Auswertungsstrategie Beispiel → → → → → let let let let 3*3 9 P raktische Inf ormatik x x x x = = = = 1, W S (1+2) in x*x 3 in x*x 3 in 3*x 3 in 3*3 2004/05, F olien Haskell−3, arithmetische Auswertung Kopieren Kopieren gc arithmetische Auswertung (8. Dezember2004) Seite 66 Beispiel let-Reduktion: fakt let fakt = \x -> if x <= 1 then 1 else x*(fakt (x-1)) in fakt Auswertung der Anwendung auf 5 ergibt: (let fakt= \x -> if x<=1 then 1 else x*(fakt (x-1)) in fakt) 5 let fakt=... in (fakt 5) let fakt=... in ((\y -> ...) 5) let fakt=... in (let y=5 in if y<=1 then 1 else y*(fakt (y-1)) let fakt=...;y=5 in if y<=1 then 1 else y*(fakt (y-1)) let fakt=...;y=5 in if 5<=1 then 1 else y*(fakt (y-1)) let fakt=...;y=5 in if False then 1 else y*(fakt (y-1)) let fakt=...;y=5 in y*(fakt (y-1)) let fakt=...;y=5 in 5*(fakt (y-1)) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 67 Beispiel let-Reduktion: fakt(2) let fakt=..;y=5 in 5*((\z->...) (y-1)) let fakt=..;y=5 in 5*(let z=(y-1) in if z<=1 then 1 else z*(fakt (z-1))) let fakt=..;y=5 in 5*(let z=(5-1) in if z<=1 then 1 else z*(fakt (z-1))) let fakt=.. in 5*(let z=(5-1) in if z<=1 then 1 else z*(fakt (z-1))) let fakt=.. in 5*(let z=4 in if z<=1 then 1 else z*(fakt (z-1))) let fakt=.. in 5*(let z=4 in if 4<=1 then 1 else z*(fakt (z-1))) let fakt=.. in 5*(let z=4 in if False then 1 else z*(fakt (z-1))) let fakt=.. in 5*(let z=4 in z*(fakt (z-1))) .... let fakt=.. in 5*(4*(3*(2*1))) ... let fakt=.. in 120 120 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 68 Allgemeine Methoden: Funktionen als Argumente Funktionen höherer Ordnung Beispiele für (arithmetische) Aufgabenstellungen: Nullstellenbestimmung, Integrieren, Differenzieren, Ermitteln von Maxima, Minima von Funktionen . . . P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 69 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]. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 70 Nullstellenbestimmung: Programm (1) f a Parameter: b genau Name der arithmetischen (Haskell-) Funktion Intervall-Anfang Intervall-Ende Genauigkeit der Nullstelle (absolut) suche_nullstelle f a b genau = let fa = f a fb = f b in if fa < 0 && fb > 0 then suche_nullstelle_steigend f a b genau else if fa > 0 && fb < 0 then suche_nullstelle_fallend f a b genau else error ("Werte haben gleiches Vorzeichen" ++ (show a) ++ (show b)) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 71 Nullstellenbestimmung: Programm (2) suche_nullstelle_steigend f a b genau = suche_nullstelle_r suche_nullstelle_fallend f a b genau = suche_nullstelle_r suche_nullstelle_r f a b genau = let m = (mittelwert a b) in if abs (a - b) < genau then m else let fm = f m in if fm > 0 then suche_nullstelle_r f a m genau else if fm < 0 then suche_nullstelle_r f m b genau else m P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 72 f a b genau f b a genau 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> P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 73 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) Unter der Annahme, dass die Implementierung der arithmetischen Funktion f O(1) Zeit und Platz braucht. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 74 Beispiel:Verwendung der Nullstellensuche √ n a n-te Wurzel aus einer Zahl a: nte_wurzel n a = suche_nullstelle (\x-> x^n -a) 1 (a^n) 0.00000001 *Main> nte_wurzel 10 1024 2.00000000372529 *Main> nte_wurzel 10 10 1.2589254114675787 *Main> (nte_wurzel 10 10)^10 9.999999974058156 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 75 Funktionen als Ergebnis Beispiel: Komposition von Funktionen: komp::(a -> b) -> (c -> a) -> c -> b komp f g x = f (g x) (sin ‘komp‘ quadrat) entspricht sin(x2) und quadrat ‘komp‘ sin entspricht (sin(x))2. *Main> suche_nullstelle (sin ‘komp‘ quadrat) 1 4 0.00000001 1.772453852929175 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 76 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 Typ Typ Typ Typ von komp von f1 von f2 des Arguments x der Komposition f1 . f2 des Resultats der Komposition f1(f2 x) f1 ‘komp‘ f2:: c -> b. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 77 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 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 78 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) f (y1) statt y1 − 0 f (y1) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 79 Variante der Newtonschen Methode zur Bestimmung der Nullstellen (2) 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 Beispiel: Nullstelle der Funktion x2 − x mit Startwert 4. *Main> newton_nst (\x -> x^2-x) 4 1.0000000000001112 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 80 0.00001 y) 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 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 81 Standards zu Basisdatentypen IEEE-Standards zu P raktische Inf ormatik 1, W S Zahlen und Operationen Genauigkeit Rundungsalgorithmus ∗, /-Algorithmen Fehlermeldungen: 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 82 Überlauf/Unterlauf, Division durch 0 UniCode internationaler Kodierungsstandard für Zeichen. • UniCode: 4 Bytes pro Zeichen – Die Zeichen (fast) aller Sprachen sind berücksichtigt – Unicode-Standard (www.unicode.org). – drei Varianten: verschiedene Kompressionen – in Haskell und in Python verfügbar P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 83 Zusammengesetzte Daten-Objekte Paar: Beispiele P raktische Inf ormatik (x, y) (1, 2) (1, "hallo") (1,(2,"hallo")) 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 84 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: P raktische Inf ormatik 1, W S z.B. toRational, truncate. 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 85 n-Tupel von Objekten Als Verallgemeinerung von Paaren (t1, . . . , tn) ist n-Tupel von t1, . . . , tn Beispiele P raktische Inf ormatik (1,2,3,True) (1,(2,True),3) ("hallo",False) (fakultaet 100,\x-> x) 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 86 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. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 87 Beispiel n-Tupel n-Tupelkonstruktor t1, . . . , tn −→ (t1, . . . , tn) Tupelselektoren n Selektoren: pro Stelle ein Selektor n-Tupel haben einen impliziten Konstruktor: (., . . . , .) | {z } n P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 88 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_1_von_3 (x1,x2,x3) = x1 selektiere_2_von_3 (x1,x2,x3) = x2 selektiere_3_von_3 (x1,x2,x3) = x3 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 89 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_3_von_3 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 90 Benutzerdefinierte Konstruktoren In Haskell mittels data-Anweisung Beispiel data Punkt = Punktkonstruktor Double Double deriving (Show, Eq) data Strecke = Streckenkonstruktor Punkt Punkt deriving (Show, Eq) data Viertupel a b c d = Viertupelkons a b c d deriving (Show, Eq) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 91 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 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 92 } 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 Beispiel (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)} P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 93 in ... Auswertung unter Benutzung von Mustern (2) Beispiel (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)} P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 94 in ... Musteranpassung anpassen Muster Ausdruck Ergebnis ist eine Menge von Bindungen: • anpassen Kon Kon = ∅ • anpassen x t = {x → t}: (passt; aber keine Bindung notwendig.) (x wird an t gebunden.) • anpassen (Kon p1 . . . pn) (Kon t1 . . . tn) = (anpassen p1 t1) ∪ . . . ∪ (anpassen pn tn) • anpassen (Kon s1 . . . sn) (Kon0 t1 . . . tm = Fail, wenn Kon 6= Kon0. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 95 Musteranpassung: weitere Möglichkeiten Variablen für Zwischenstrukturen in Mustern: Beispiel (x,y@(z_1,z_2)) anpassen an (1, (2,3)) ergibt: x = 1, y = (2,3), z_1 = 2, z_2 = 3. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 96 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] deriving(Show,Eq) deriving(Show,Eq) deriving(Show,Eq) deriving(Show,Eq) Typ und Konstruktor können gleiche Namen haben. Der Parameter a kann jeder Typ sein: z.B.: Float, Int, aber auch [[(Int, Char)]] P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 97 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)))) verschiebeStrecke s v = let (Strecke (Punkt a1 a2) (Punkt b1 b2)) = s (Vektor v1 v2) = v in (Strecke (Punkt (a1+v1) (a2+v2)) (Punkt (b1+v1) (b2+v2))) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 98 Funktionen auf Punkt, Strecke, Polygonzug (2) teststrecke = (Strecke (Punkt 0 0) (Punkt 3 4)) test_streckenlaenge = streckenLaenge (verschiebeStrecke teststrecke (Vektor 10 (-10))) -------------------------------------------------------streckenLaenge teststrecke <CR> > 5.0 test_streckenlaenge <CR> > 5.0 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 99 Typen der Funktionen addiereVektoren :: Num a => Vektor a -> Vektor a -> Vektor a streckenlaenge :: Num a => Strecke a -> Float test_streckenlaenge :: Float verschiebeStrecke :: Num a => Strecke a -> Vektor a -> Strecke a P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 100 Summentypen und Fallunterscheidung Summentyp: definiert durch die Bedingung: hat 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) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 101 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 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) -Seite 102 Joker, Wildcard Fallunterscheidung mit case Für Summentypen ist eine neue Reduktionsregel notwendig: 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 ist äquivalent zu und2, und3) und &&: und4 x y = case x of True -> y; False -> False nichtleer lst = case lst of [] -> False (x:t) -> True P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 103 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 (case s of (c1 x11 . . . x1n1 → t1); . . . ; (ck xk1 . . . xknk → tk )) = GV (s) ∪ GV (t1) ∪ {x11, . . . x1n1 } ∪ . . . ∪ GV (tk ) ∪ {xk1, . . . xknk } P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 104 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} P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 105 Fallunterscheidung if-then-else Die Definition mein_if x y z = case x of True -> y; False -> z ist äquivalent zum if . then . else P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 106 Reduktionsregel zum case case-Reduktion (case (c t1 . . . tn) of . . . (c x1 . . . xn → s) . . .) let {x1 = t1; . . . ; xn = tn} in s P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 107 case-Reduktion: Beispiele dmoderdollar x = case x of (Dm wert) -> True; (Dollar wert) -> True; Euro _ -> False; SFranken _ -> False ---------------------------------dmoderdollar (Dollar 10) --> case (Dollar 10) of (Dm wert) -> True; (Dollar wert) -> True; Euro _ -> False; SFranken _ -> False --> let wert = 10 in True --> True P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 108 Reduktionsregel zum case dmoderdollarwert x = case x of (Dm wert) -> wert; (Dollar wert) -> wert; Euro _ -> 0; SFranken _ -> 0 --------------------------dmoderdollarwert (Dollar 10) --> case (Dollar 10) of (Dm wert) -> wert; (Dollar wert) -> wert; Euro _ -> 0; SFranken _ -> 0 --> let wert = 10 in wert --> let wert = 10 in 10 --> 10 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 109 Funktionsdefinitionen: Strategie Fallunterscheidungen mit Mustern in Funktionsdefinitionen: können als case-Ausdrücke geschrieben werden. Haskell erlaubt überlappende Muster Musteranpassungsstrategie in Funktionsdefinitionen mit Mustern und Wächtern: Muster von oben nach unten, bis Muster passt und Wächter = True Es gilt: P raktische Inf ormatik Diese Strategie ist zur Compilezeit in geschachtelte case-Ausdrücke transformierbar 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 110 Funktionsdefinitionen: Beispiel f (Euro x) f (Dollar x) f x = = = "Euro" "US Dollar" "andere " f y = case y of (Euro x)-> "Euro"; (Dollar x)-> "Dollar"; (Dm x)-> "andere"; (SFranken x) -> "andere"; P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 111 Auswertung in Haskell Kombination von Transformation und Auswertung: Haskell- Programm Entzuckerung Programm in Kernsprache Syntaxanalyse Syntaxbaum des Programms Auswertung (operationelle Semantik) transformierter Syntaxbaum P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 112 Entzuckerung: Beispiel map f [] map f (x:xs) = [] = f x : map f xs kann man transformieren zu: map f lst P raktische Inf ormatik = (case lst of [] -> []; (x:xs) -> f x : map f xs) 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 113 Bemerkungen zu Church-Rosser-Sätzen • Die Church-Rosser-Sätze gelten bei nicht-rekursivem let wenn keine Konstruktoren benutzt werden. • Die Church-Rosser-Sätze gelten nicht mehr bei rekursivem let • analoge Aussagen gelten noch Hierzu benötigt man das Konzept der Verhaltensgleichheit ∼ von Ausdrücken P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 114 Verhaltensgleichheit Man kann eine Verhaltensgleichheit ∼ definieren, so dass gilt: • • • verschiedene Basiswerte a, b sind nicht verhaltensgleich: a 6= b ⇒ a 6∼ b man kann Gleiches durch Gleiches ersetzen: s ∼ t ⇒ P [s] ∼ P [t] Reduktion erhält Verhaltensgleichheit: s→t⇒s∼t Die Folgerungen sind weitreichend: Z.B. ist es korrekt, alle Auswertungen bereits im Compiler zu machen. Das ist in anderen Programmiersprachen nur in sehr eingeschränkten Fällen korrekt. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 115 Rekursive Datenobjekte: Listen, Bäume, . . . Listen: Nochmal Eine eigene Definition des Datentyps Liste: data Liste a = Leereliste | ListenKons a (Liste a) a : Typ der Objekte in der Liste Rekursiver Datentyp! P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 116 Listen in Haskell Listen sind in Haskell eingebaut mit syntaktischer Sonderbehandlung So würde die Definition aussehen (Im Prinzip korrekt) data [a] = [] | a : [a] P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 117 Listenausdrücke, (list comprehensions) Syntax: [hAusdrucki "|" hGeneratori | hFilteri{, {hGeneratori | hFilteri}}∗]. Analog zu Mengenausdrücken, Z.B. {x | x < 3, x ∈ IN} aber Reihenfolge der Listenelemente im Resultat wird festgelegt. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 118 Beispiele: [x [f x [x [(x,y) | | | | [y | x <- xs, y <-x] P raktische Inf ormatik x x x x 1, W S <<<<- xs] xs] xs, p x] xs, y <-ys] 2004/05, F olien Haskell−3, = = = = = (8. Dezember2004) xs map f xs filter p xs xs × ys (Kreuzprodukt) für endliche Listen concat xs Seite 119 Listen-Komprehensionen [Resultatausdruck | Generatoren,Testfunktionen] Generator: Prädikat: v <- liste Test auf True/False. generiert Elemente von liste Element wird akzeptiert/nicht akz. Wirkungsweise: die Generatoren liefern nach und nach die Elemente der Listen. Wenn alle Prädikate zutreffen, wird Resultatausdruck in die Resultatliste aufgenommen. neue lokale Variablen sind möglich. Deren Geltungsbereich ist rechts von der Einführung und im Resultatausdruck und P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 120 List-Komprehensionen: Beispiel Zahlen, die nicht durch 2,3,5,7 teilbar sind zwischen 2 und 100: [x|x<-[2..100], not (even x), not (x ‘mod‘ 3 == 0), not ( x ‘mod‘ 5 == 0), not(x ‘mod‘ 7 == 0)] [11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97] P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 121 List-Komprehensionen: Beispiel [(x,y) | x <- [1..10], even x, y <- [2..6], x < y] Resultat: [(2,3),(2,4),(2,5),(2,6),(4,5),(4,6)] Begründung: Erzeugungsreihenfolge: x y ? 1 N 2 2 N P raktische Inf ormatik 2 3 Y 1, W S 2 4 Y 2 5 Y 2 6 Y 2004/05, F olien Haskell−3, 3 N 4 2 N (8. Dezember2004) 4 3 N 4 4 4 5 6 ... 4 5 6 2 ... N Y Y N N ... Seite 122 List-Komprehensionen: Beispiel [(x,y) | x <- [1..10], y <- [1..x]] [(1,1), (2,1),(2,2), (3,1),(3,2),(3,3), (4,1),(4,2),(4,3),(4,4), (5,1),(5,2),(5,3),(5,4),(5,5), (6,1),(6,2),(6,3),(6,4),(6,5),(6,6), (7,1),(7,2),(7,3),(7,4),(7,5),(7,6),(7,7), (8,1),(8,2),(8,3),(8,4),(8,5),(8,6),(8,7),(8,8), (9,1),(9,2),(9,3),(9,4),(9,5),(9,6),(9,7),(9,8),(9,9), (10,1),(10,2),(10,3),(10,4),(10,5),(10,6),(10,7),(10,8),(10,9),(10,10)] P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 123 Beispiel: einfache geometrische Algorithmen • Fläche eines Dreiecks • Polygonfläche • Test auf Konvexität Generelles Problem der geometrischen Algorithmen: Sonderfälle Beispiel P raktische Inf ormatik Fläche eines regelmäßigen n-Ecks Fläche des Umkreises Vergleich 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 124 Funktionen zu geometrischen Algorithmen konvexer Polygonzug p1, . . . , p5 p4 p3 p5 p2 p1 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 125 Funktionen zu geometrischen Algorithmen data data data data Punkt a Strecke a Vektor a Polygon a = = = = Punkt a a deriving(Show,Eq) Strecke (Punkt a) (Punkt a) deriving(Show,Eq) Vektor a a deriving(Show,Eq) Polygon [Punkt a] deriving(Show,Eq) -polgonflaeche data Polygon a = Polygon [Punkt a] deriving(Show,Eq) -- Annahme: Polygonz"uge sind geschlossen polyflaeche poly = if ist_konvex_polygon poly then polyflaeche_r poly else error "Polygon ist nicht konvex" polyflaeche_r (Polygon (v1:v2:v3:rest)) = dreiecksflaeche v1 v2 v3 + polyflaeche_r (Polygon (v1:v3:rest)) polyflaeche_r _ = fromInt 0 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 126 Funktionen zu geometrischen Algorithmen(2) dreiecksflaeche v1 v2 v3 = let a = abstand v1 v2 b = abstand v2 v3 c = abstand v3 v1 s = 0.5*(a+b+c) in sqrt (s*(s-a)*(s-b)*(s-c)) abstand (Punkt a1 a2 ) (Punkt b1 b2 ) = let d1 = a1-b1 d2 = a2-b2 in sqrt (d1^2 + d2^2) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 127 Funktionen zu geometrischen Algorithmen(3) Normierung: Elimination von gleichen Punkten Elimination von kollinearen Tripeln poly_norm (Polygon x) = let eqnorm = (poly_normeq_r x) kollnorm = poly_norm_koll2 (poly_norm_koll eqnorm) in Polygon kollnorm poly_normeq_r [] = [] poly_normeq_r [x] = [x] poly_normeq_r (x:rest@(y:_)) = if x == y then poly_normeq_r rest else x: poly_normeq_r rest P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 128 Funktionen zu geometrischen Algorithmen (4) poly_norm_koll (x:rest1@(y:z:tail)) = if poly_drei_koll x y z then poly_norm_koll (x:z:tail) else x:poly_norm_koll rest1 poly_norm_koll rest = rest poly_norm_koll2 (x:rest) = if length rest < 2 then x:rest else let y = last rest z = rest !! (length rest -2) in if poly_drei_koll z y x then rest else if poly_drei_koll y x (rest !! 0) then rest else x:rest P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 129 Funktionen zu geometrischen Algorithmen (5) --testet x,y,z auf Kollinearitaet: poly_drei_koll (Punkt x1 x2) (Punkt y1 y2) (Punkt z1 z2) (z1-y1)*(y2-x2) == (y1-x1)*(z2-y2) --- (z1-y1)/(z2-y2) == (y1-x1)/(y2-x2) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 130 = Funktionen zu geometrischen Algorithmen (6) -- testet Konvexitaet: aber nur gegen den Uhrzeigersinn. ist_konvex_polygon (Polygon []) = True ist_konvex_polygon (Polygon [p,q]) = True ist_konvex_polygon (Polygon (alles@(p:q:polygon))) = ist_konvex_polygonr (alles ++ [p,q]) ist_konvex_polygonr (p1:rest@(p2:p3:rest2)) = ist_konvex_drehung_positiv p1 p2 p3 && ist_konvex_polygonr rest ist_konvex_polygonr _ = True ist_konvex_drehung_positiv (Punkt a1 a2) (Punkt b1 b2) (Punkt c1 c2) = let ab1 = a1-b1 ab2 = a2-b2 bc1 = b1-c1 bc2 = b2-c2 in ab1*bc2-ab2*bc1 > 0 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 131 Geometrische Algorithmen. Beispiel *Main> testpolygon Polygon [Punkt 1 1,Punkt 2 2,Punkt 3 3,Punkt 3 3, Punkt 0 3,Punkt (-1) (-1),Punkt 0 (-2)] *Main> poly_norm testpolygon Polygon [Punkt 1 1,Punkt 3 3,Punkt 0 3,Punkt (-1) (-1),Punkt 0 (-2)] *Main> P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 132 Funktionen zu geometrischen Algorithmen: Vieleck vieleck n = Polygon [Punkt (cos (2.0*pi*i/n)) (sin (2.0*pi*i/n)) | i <- [1.0..n]] vieleckflaeche n = polyflaeche (vieleck n) vieleck_zu_kreis n = let kreis = pi vieleck = vieleckflaeche n ratio = vieleck / kreis in (n,kreis, vieleck,ratio) *Main> vieleckflaeche 100000 3.1415926515204107 *Main> pi 3.141592653589793 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 133 Funktionen auf Listen: fold foldl (Linksfaltung) foldr (Rechtsfaltung) Argumente: eine zweistellige Operation ein Anfangselement (Einheitselement) die Liste 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) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 134 foldl und foldr foldl ⊗ e [a1, . . . , an] entspricht ((. . . ((e ⊗ a1) ⊗ a2) . . . ) ⊗ an). foldr ⊗ e [a1, . . . , an] entspricht a1 ⊗ (a2 ⊗ (. . . (an ⊗ e))) Wenn ⊗ assoziativ, e Rechts- und Linkseins zu ⊗, und Liste lst endlich, dann gleicher Wert für (foldl ⊗ e lst) und (foldr ⊗ e lst) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 135 Verwendungsbeispiele sum xs = foldl (+) 0 xs produkt xs = foldl (*) 1 xs ----- concat xs = foldr (++) [] xs Main> sum [1..10] 55 :: Integer Main> product [1..10] 3628800 :: Integer Main> concat [[1,2],[3,4],[5,6]] [1,2,3,4,5,6] :: [Integer] P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 136 (foldl’ (*) 1 xs) Beispiel: Reduktion mit foldl foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z [] = z foldl f z (x:xs) = foldl f (f z x) xs Reduktion (vereinfacht): foldl (*) foldl (*) foldl (*) foldl (*) ((*) ((*) P raktische Inf ormatik 1 [1,2,3] ((*) 1 1) ((*) ((*) ((*) ((*) ((*) 1 1) 1, W S [2,3] 1 1) 2) [3] ((*) 1 1) 2) 3) [] 2) 3) 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 137 Beispiel: Reduktion mit foldr foldr :: (a -> b -> b) -> b -> [a] -> b foldr f z [] = z foldr f z (x:xs) = f x (foldr f z xs) Reduktion (vereinfacht): foldr (*) 1 [1,2,3] ((*) 1 (foldr (*) 1 [2,3])) ((*) 1 ((*) 2 (foldr (*) 1 [3]))) ((*) 1 ((*) 2 ((*) 3 (foldr (*)1 [])))) ((*) 1 ((*) 2 ((*) 3 1))) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 138 Speicher-optimiertes foldl foldl’ :: (a -> b -> a) -> a -> [b] -> a foldl’ f a [] = a foldl’ f a (x:xs) = ((foldl’ f) $! (f a x)) xs fun $! x entspricht: Zuerst x auswerten, dann f x Beachte: Nur sinnvoll, wenn Ergebnisse von f Basiswerte sind P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 139 Ressourcenbedarf von foldl, foldr, foldl’ foldl und foldr haben unterschiedlichen Ressourcenbedarf in Abhängigkeit vom Operator foldl’ ist speicher-optimiertes foldl foldr (++) [] xs ist schneller als foldl (++) [] xs foldl’ (+) 0 xs braucht weniger Platz als foldr (+) 0 xs Main> length (foldr (++) [] [[x] | x <- [1..1000]]) 1000 :: Int (29036 reductions, 43060 cells) Main> length (foldl (++) [] [[x] | x <- [1..1000]]) 1000 :: Int (527532 reductions, 1539550 cells, 6 garbage collections) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 140 Weitere Listen-Funktionen Umdrehen einer Liste: reverse_naiv [] reverse_naiv (x:xs) = [] = (reverse_naiv xs) ++ [x] effizientes Umdrehen einer Liste: reverse xs = foldl (\x y -> y:x) [] xs P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 141 Weitere Listen-Funktionen Restliste nach n-tem Element drop drop drop drop 0 _ n _ xs [] (_:xs) | n>0 _ = = = = xs [] drop (n-1) xs error "Prelude.drop: negative argument" Liste der Paare: zip :: [a] -> [b] -> [(a,b)] zip (a:as) (b:bs) = (a,b) : zip as bs zip _ _ = [] macht aus Liste von Paaren ein Paar von Listen unzip unzip :: [(a,b)] -> ([a],[b]) = foldr (\(a,b) (as,bs) -> (a:as, b:bs)) ([], []) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 142 Beispiele drop 10 [1..100] -----> zip "abcde" [1..] -----> [11,12,... [(’a’,1),(’b’,2),(’c’,3),(’d’,4),(’e’,5)] unzip (zip "abcdefg" [1..]) ----> ("abcdefg",[1,2,3,4,5,6,7]) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 143 Ressourcenbedarf von Listenfunktionen Drei Möglichkeiten der Auswertung: Komplett-Auswertung z.B. beim Drucken der Ergebnisliste im Interpreter Rückgrat-Auswertung nur soviel, wie length von der Ergebnisliste benötigt Kopf-Auswertung nur soviel, dass die Frage Ist die Ergebnisliste leer oder nicht leer “ ” beantwortet werden kann. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 144 Ressourcenbedarf von Listenfunktionen. Beispiele lengthr [] = 0 lengthr (x:xs) = 1+lengthr xs length_lin xs = length_linr 0 xs length_linr s [] = s length_linr s (x:xs) = (length_linr $! (s+1)) xs Wenn lst bereits ausgewertet ist, und Länge n hat: lengthr lst length_lin lst P raktische Inf ormatik 1, W S benötigt O(n) Reduktionsschritte und O(n) Platz. benötigt O(n) Reduktionsschritte und O(1) Platz. 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 145 Ressourcenbedarf von Append xs,ys seien ausgewertete Listen der Länge m und n. [] ++ ys = ys (x:xs) ++ ys = x:(xs++ys) Bei Rückgrat-Auswertung: xs ++ ys benötigt O(m + n) Reduktionsschritte O(m) Platz: nur das Rückgrat muss kopiert werden P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 146 Ressourcenbedarf von map xs sei ausgewertete Liste der Länge n map f xs: Rückgratauswertung: O(n) Reduktionsschritte O(n) Speicherbedarf Komplett-Auswertung: # Reduktionsschritte abhängig von f Speicherbedarf abhängig von f P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 147 Ressourcenbedarf von concat Sei xs ausgewertete Liste von Listen der Länge m, das i-te Element sei eine Liste mit ni Elementen. [ [a1,1, a1,2, . . .], . . . , [am,1, am,2, . . . ] ] {z } | {z } | n1 nm | {z m concat [] concat (x:xs) } = [] = x ++ (concat xs) Rückgratauswertung von concat xs : bei Reduktionsschritte: n1 + n2 + . . . nm + m Platzbedarf: O(n1 + . . . + nm−1 + m) letzte Liste muss nicht kopiert werden P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 148 Einige abstrakte Datentypen Stack (bzw. Keller, Stapel) Auch last-in first-out bzw. lifo Operationen: push pop ist leer Legt Element auf den Stack Nimmt ein Element vom Stack Prüft, ob Stack leer ist. Implementierung: mit Listen P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 149 Stack: Anwendungen • rekursive Auswertung von Ausdrücken • Verwaltung von Prozeduraufrufen zur Laufzeit • Umdrehen einer Liste reverse xs = foldl (\x y -> y:x) [] xs P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 150 Queue, Warteschlange Vorne wird bedient (abgearbeitet), und hinten angestellt first-in first out bzw. fifo Implementierung mittels Listen: q_neu x q = x:q q_weg q = (qletztes q, qrest q) qletztes [ ] = error "Schlange ist leer" qletztes [x] = x qletztes (x:xs) = qletztes xs qrest [x] = [] qrest (x:xs) = x: qrest xs P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 151 Assoziationsliste Liste von Schlüssel-Wert Paaren: [(k1, w1), (k2, w2), (k3, w3), . . . , ] Funktionen: Eintragen, Löschen, Ändern, Abfragen. Beispiel für Assoziationsliste: [(’0’,0), (’1’,1), ... , Verwendung von Assoziationslisten: z.B. bei der Erstellung von Arrays bei Abänderung von Arrays P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 152 (’9’,9)]. Assoziationsliste: Funktionen mkassocl = [] ascfinde x [] = Nothing ascfinde x ((xk,xw):rest) = if x == xk then Just xw else ascfinde x rest asceinf x w [] = [(x,w)] asceinf x w ((xk,xw):rest) = if x == xk then ((xk,w):rest) else (xk,xw) : (asceinf x w rest) ascremove x [] = [] ascremove x ((xk,xw):rest) = if x == xk then rest else (xk,xw):(ascremove x rest) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 153 Felder, Arrays Feld, Array: Folge ai von Datenobjekten für i = 0, . . . , n Typisch: Zugriff mit Index Zugriff auf a[i] in konstanter Zeit Python: Listen sind auch Arrays Listen von Referenzen auf Werte heterogene Listen Haskell: Arrays als extra Modul destruktive Änderungen sind unmöglich homogene Listen P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 154 Mehrdimensionale Felder Haskell: Indextyp: geschachtelte Tupel von Int Variante 2: Arrays von Arrays Python: P raktische Inf ormatik Liste von Listen . . . von Listen 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 155 Felder in Haskell: Funktionen • array x y : neues Array mit Grenzen x = (start, ende), initialisiert mittels y = Liste von Index-Wert Paaren (eine Assoziationsliste) • listArray x y: neues Array mit Grenzen x = (start, ende), initialisiert sequentiell anhand der Liste y. • ! : Infix funktion: ar!i ergibt das i-te Element des Feldes ar. • // : Infix-funktion a // xs; neues Feld, abgeändert entsprechend der Assoziationsliste xs. • bounds: Indexgrenzen des Feldes. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 156 Felder in Haskell: Beispiele *Main> let a = array (1,10) (zip [1..10] [1..]) *Main> a array (1,10) [(1,1),(2,2),(3,3),(4,4),(5,5), (6,6),(7,7),(8,8),(9,9),(10,10)] *Main> a!1 1 *Main> [a!i| i <-[1..10]] [1,2,3,4,5,6,7,8,9,10] P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 157 Felder in Haskell: Beispiele *Main> let a = array (1,10) (zip [1..10] [1..]) *Main> let b = a // (zip [1..5] [100,200..]) *Main> b array (1,10) [(1,100),(2,200),(3,300),(4,400),(5,500), (6,6),(7,7),(8,8),(9,9),(10,10)] *Main> bounds a (1,10) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 158 Felder in Haskell: Beispiele umdrehen_array ar = let (n,m) = bounds ar mplusn = m+n in ar // [(i,ar!(mplusn -i)) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 159 | i <- [n..m] ] Mehrdimensionale Felder in Haskell: Beispiele transpose_matrix ar = let ((n1,m1),(n2,m2)) = bounds ar assocl = [((i,j), ar!(j,i)) | j <- [n1..n2], i <- [m1..m2]] in array ((m1,n1), (m2,n2)) assocl P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 160 Mehrdimensionale Felder in Haskell: Tests *Main> let testmatrix = array ((1,1),(3,4)) [((i,j), (show i) ++ " " ++ (show j)) | i <- [1..3], j <- [1..4]] *Main> testmatrix array ((1,1),(3,4)) [((1,1),"1 1"),((1,2),"1 2"),((1,3),"1 3"),((1,4),"1 4"), ((2,1),"2 1"),((2,2),"2 2"),((2,3),"2 3"),((2,4),"2 4"), ((3,1),"3 1"),((3,2),"3 2"),((3,3),"3 3"),((3,4),"3 4")] *Main> [[testmatrix!(x1,x2) | x2 <- [1..4]] | x1 <- [1..3]] [["1 1","1 2","1 3","1 4"],["2 1","2 2","2 3","2 4"], ["3 1","3 2","3 3","3 4"]] P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 161 Matrizenmultiplikation matmult a b = let ((a11,a12),(a21,a22)) = bounds a ((b11,b12),(b21,b22)) = bounds b in if a11 /= 1 || a12 /= 1 || b11 /= 1 || b12 /= 1 || a22 /= b21 then error "Arrays haben falsche Grenzen" else array ((1,1),(a21,b22)) [( (x,y), skalarprod [a!(x,z) | z <- [1..a22]] [b!(z,y) | z <- [1..a22]] ) | x <- [1..a21], y <- [1..b22]] skalarprod xs ys = foldl (\z (x,y) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 162 -> x*y+z) 0 (zip xs ys) Matrizenmultiplikation *Main> let ar3 = array ((1,1),(2,3)) [((i,j),1) | i <- [1..2], j <- [1..3]] *Main> let ar4 = array ((1,1),(3,4)) [((i,j),1) | i <- [1..3], j <- [1..4]] *Main> print2ar ar3 [[1,1,1],[1,1,1]] *Main> print2ar ar4 [[1,1,1,1],[1,1,1,1],[1,1,1,1]] *Main> print2ar (matmult ar3 ar4) [[3,3,3,3],[3,3,3,3]] P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 163 Ein-Ausgabe in Haskell. Kurzeinführung: Ein-Ausgabe mittels IO-Aktionen Typ: a1 -> a2 ... -> IO a, Spezialfall: IO a Ein/Ausgabe durch Auswerten eines Ausdrucks vom Typ IO a a: Typ des Eingabe. Falls keine Eingabe, dann IO () P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 164 Vordefinierte Basis-IO-Aktionen putStr:: String -> IO () putStrLn:: String -> IO () getLine:: IO String print:: (Show a) => a -> IO () readLn: (Read a) => IO a type FilePath writeFile :: appendFile :: readFile :: = String FilePath -> String -> IO () FilePath -> String -> IO () FilePath -> IO String putStr, putStrLn und print geben ihr Argument aus print und readLn sind polymorph. Verwendete Methode ist abhängig vom statisch ermittelten Typ P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 165 Beispiele Das Hello-World-Programm: *Main> putStr "Hello World" Hello World*Main> P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 166 DO-Notation do-Notation analog zu Listen-Komprehensionen bewirkt Kombination von Aktionen Ermöglicht Definition von neuen IO-Aktionen mittels vordefinierter IO-Aktionen Kontrollierte Selektion der Eingabe aus IO-Objekten do ... arg <- ... wirkt wie ein Selektor, Beispiel do {input <- getLine; putStr input} äquivalent dazu ist: do input <- getLine putStr input P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 167 Beispiel im Interpreter *Main> do {input <- getLine; Hello -Hello -*Main> P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, putStrLn input} eingetippt Ausgabe (8. Dezember2004) Seite 168 Programmierbeschränkungen zu IO Kombination von Typisierung eingeschränkter Satz von vordefinierten IO-Aktionen nur do-Notation darf selektieren bewirkt Programmierbeschränkungen: Trennung von Ein/Ausgabe und Auswertung Sequentialisierung der Ein-Ausgaben P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 169 Beispiele echoLine:: IO String echoLine = do input <- getLine putStr input Einlesen einer Int-Zahl getNumber:: IO Int getNumber = do putStr "Bitte eine Zahl eingeben:" readLn P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 170 Beispiele Parametrisierte Listen-Ausgabe: main = do a <- getNumber b <- getNumber print (take a (repeat b)) *Main> main Bitte eine Zahl eingeben:4 Bitte eine Zahl eingeben:6 [6,6,6,6] P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 171 Beispiele File lesen und ausgeben: fileLesen = do putStr "File-Name:?" fname <-getLine contents<-readFile fname putStr contents P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 172 Beispiele Wiederholte Nachfrage, ob (E)rgebnis gewünscht oder (W)eiter? weiter = do putStrLn "(E)rgebnis oder (W)eiter?" w <- getLine case (head w) of ’E’ -> return False ’W’ -> return True other -> weiter Rekursive Definition einer Aktion. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 173 Beispiele Addieren beliebig vieler Zahlen addiere = addiere_ 0 addiere_ x = do a <- getNumber w <- weiter if w then addiere_ (a+x) else putStrLn ("Das Ergebnis ist " ++ (show (a + x))) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 174 Beispiele Addieren beliebig vieler Zahlen mit Speicherung der Eingabe addiereS = addiereS_ [] addiereS_ xs = do a <- getNumber w <- weiter if w then addiereS_ (a:xs) else putStrLn $ (concat $ intersperse (" + ") ((reverse .map show) (a:xs))) ++ " = " ++ (show (sum (a:xs))) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 175 Modularisierung in Haskell Module dienen zur • Strukturierung / Hierarchisierung • Kapselung: • Wiederverwendbarkeit: P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 176 Definition eines Moduls Zum Modul gehören: Funktionen, Datentypen, Typsynonyme können exportiert werden, von anderen Modulen importiert werden Syntax module Modulname (Exportliste ) where Modulimporte , M odulrumpf Datentypdefinitionen , Funktionsdefinitionen , . . . Für jedes Modul muss eine separate Datei angelegt werden, wobei der Modulname dem Dateinamen ohne Dateiendung entsprechen muss. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 177 Programme und Module Haskell-Programm besteht aus einer Menge von Modulen Das Modul Main muss existieren und eine Funktion namens main :: IO () definieren und exportieren. Grundgerüst eines Haskell-Programms: module Main(main) where ... main = ... ... P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 178 Modulexport und -import Beispiel module Spiel where data Ergebnis = Sieg | Niederlage | Unentschieden berechneErgebnis a b = if a > b then Sieg else if a < b then Niederlage else Unentschieden istSieg Sieg = True istSieg _ = False istNiederlage Niederlage = True istNiederlage _ = False Exportliste: Funktionen oder Typen mit oder ohne Konstruktoren auch importierte Namen können wieder exportierten werden P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 179 Modulimport Mittels import am Anfang des Modulrumpfs. Varianten: import Modulname import Modulname(N1,N2,...) import Spiel hiding(...) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) importiert alle Einträge der Exportliste von Modulname importiert spezifizierte Namen von Modulname importiert alles bis auf ... Seite 180 Aufruf von Funktionen: Namenskonventionen Aufruf von importierten Funktionen: mit unqualifizierten Namen mitModulname.unqualifizierter Name Beispiel zur Notwendigkeit qualifizierter Namen: module A(f) where f a b = a + b module B(f) where f a b = a * b module C where import A import B g1 = f 1 2 + f 3 4 g2 = A.f 1 2 + B.f 3 4 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, -- funktioniert nicht -- funktioniert (8. Dezember2004) Seite 181 Übersicht zur Sichtbarkeit der Namen Modul M exportiert f und g, Import-Deklaration import M import M() import M(f) import qualified M import qualified M() import qualified M(f) import M hiding () import M hiding (f) import qualified M hiding () import qualified M hiding (f) import M as N import M as N(f) import qualified M as N P raktische Inf ormatik 1, W S 2004/05, F olien Haskell−3, (8. Dezember2004) Seite 182 definierte Namen f, g, M.f, M.g keine f, M.f M.f, M.g keine M.f f, g, M.f, M.g g, M.g M.f, M.g M.g f, g, N.f, N.g f, N.f N.f, N.g