Listen und Funktionen auf Listen

Werbung
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
Herunterladen