ALP I Funktionale Programmierung

Werbung
Funktionale Programmierung
ALP I
Funktionale Programmierung
Zusammengesetzte Datentypen in Haskell
SS 2011
Prof. Dr. Margarita Esponda
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Zusammengesetzte Datentypen
Tupel
List
String
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Zusammengesetzte Datentypen
Tupel-Datentyp
Ein Tupel ist eine Ansammlung von zwei oder mehreren
Daten, die unterschiedliche Datentypen besitzen können.
Mit Hilfe von Tupeln können zusammengehörige Daten als
Einheit behandelt werden.
Studierende
Beispiele:
( "Peter" , "Meyer", 439990 ) :: ( String, String, Int )
( 2.5, 3.0 )
:: ( Double, Double )
Punkt
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Tupel-Typ
Funktionsdefinition mit Tupeln:
distance :: (Double, Double) -> (Double, Double) -> Double
distance p1 p2 = sqrt(xd^2 + yd^2)
where
xd = (fst p1) - (fst p2)
yd = (snd p1) - (snd p2)
distance :: (Double, Double) -> (Double, Double) -> Double
distance (x1,y1) (x2,y2) = sqrt (squareX + squareY )
where
squareX = (x1-x2) * (x1-x2)
squareY = (y1-y2) * (y1-y2)
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Pattern-Matching
myNot :: Bool -> Bool
myNot True
= False
myNot False = True
oder :: Bool -> Bool -> Bool
oder
oder
False False = False
x
y
= True
oder0 :: Bool -> Bool -> Bool
oder0
False False = False
oder0
False True = True
oder0
True False = True
oder0
True True = True
und :: Bool -> Bool -> Bool
und
True
True
=
True
und
_
_
=
False
beliebige Argumente vom Typ Bool
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Pattern-Matching
In Haskell ist es möglich durch Pattern-Matching eine
Auswahl verschiedener Funktionsgleichungen zu
definieren.
Allgemeine Form:
f p11 p12 … p1n = e1
f p21 p22 … p2n = e2
…..
f pk1 pk2 … pkn = ek
Die pij Muster werden von oben nach unten und von links
nach rechts geprüft.
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Tupel-Typ
Ein Tupel-Typ hat folgende allgemeine Form:
( t1 , t2 , … , tn ), wobei t1 , t2 , … , tn beliebige
Datentypen sind
Zwei einfache Funktionen für Tupel sind:
fst (x, y) = x
snd (x, y) = y
Die erwartete Tupel-Struktur wird in den Argumenten sichtbar
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Typ-Synonyme
Typ-Synonyme werden verwendet, um die Lesbarkeit von
Programmen mit Hilfe von aussagekräftigen Typ-Namen zu
verbessern.
Allgemeine Form:
type Typname = …….
Beispiele:
type Student = (String, String, Int)
type Point = (Double, Double)
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Typ-Synonyme
Funktionsdefinition mit Typ-Synomyme:
type Point = (Double, Double)
distance :: Point -> Point -> Double
distance (x1,y1) (x2,y2) = sqrt (sumSq (x1-x2) (y1-y2))
where
sumSq x y = x*x + y*y
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Typ-Synonyme
type Complex = (Double, Double)
realPart :: Complex -> Double
realPart ( real, img ) = real
imgPart :: Complex -> Double
Text
imgPart ( real, img ) = img
sumC :: Complex -> Complex -> Complex
sumC (r1,i1) (r2,i2) = (r1+r2, i1+i2)
absC :: Complex -> Double
absC ( real, img ) = sqrt( real*real + img*img )
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Fibonacci-Zahlen
Problem:
Zu Beginn eines Jahres gibt es genau ein Paar neugeborener
Kaninchen.
Ein Paar neugeborener Kaninchen ist erst nach einem Monat
fortpflanzungsfähig, sodass erst nach zwei Monaten ein
neues Kaninchenpaar zur Welt gebracht werden kann.
Jedes nicht neugeborene Kaninchen bekommt ein neues
Kaninchenpaar monatlich.
Wie viele Kaninchen gibt es nach einem Jahr, wenn keines
der Kaninchen stirbt?
Prof. Dr. Margarita Esponda
11
Funktionale Programmierung
1
Fibonacci-Zahlen
1
2
3
5
8
Prof. Dr. Margarita Esponda
12
Funktionale Programmierung
Fibonacci-Zahlen
Der Stammbaum einer Drohne
13
8
Ururgroßeltern 5
Urgroßeltern
3
Großeltern
2
Mutter
1
Drohne
Prof. Dr. Margarita Esponda
13
Funktionale Programmierung
Fibonacci-Zahlen
8
13
5
1
1
2
3
21
Prof. Dr. Margarita Esponda
14
Blumen
Fibonacci-Zahlen
1
2
3
5
8
13
21
34
15
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Fibonacci-Zahlen
fib(0)
0
+
fib(1)
fib(2)
1
1
Prof. Dr. Margarita Esponda
16
Funktionale Programmierung
Fibonacci-Zahlen
fib(0)
fib(1)
0
1
Prof. Dr. Margarita Esponda
fib(2)
+
1
fib(3)
2
17
Funktionale Programmierung
Fibonacci-Zahlen
fib(0)
fib(1)
fib(2)
0
1
1
Prof. Dr. Margarita Esponda
fib(3)
+ 2
fib(4)
3
18
Funktionale Programmierung
Fibonacci-Zahlen
fib(0)
fib(1)
fib(2)
0
1
1
Prof. Dr. Margarita Esponda
fib(3)
2
+
fib(4)
3
fib(5)
5
19
Funktionale Programmierung
Fibonacci-Zahlen
fib(0)
fib(1)
fib(2)
fib(3)
0
1
1
2
.....
fib(4) fib(5)
3
fib(n-2) + fib(n-1)
5
fib(6)
fib(7)
+ 8
+
13
.....
fib(n)
Formale rekursive Definition:
fib ( 0 ) = 0
fib ( 1 ) = 1
fib ( n ) = fib ( n-2 ) + fib ( n-1 )
Prof. Dr. Margarita Esponda
für alle
n>1
20
Funktionale Programmierung
Berechnung der Fibonacci-Zahlen
1. Lösung
Beispiel:
fib 7
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
fib 7
fib 5
fib 3
fib 1
fib 0
fib 1
fib 6
fib 4
fib 2
fib 2
fib 0 = 0
fib 4
fib 3
fib 2
fib 5
fib 3
fib 3
fib 4
fib 0 fib 1 fib 1 fib 2 fib 0 fib 1 fib 1 fib 2 fib 1 fib 2 fib 2 fib 3
fib 0 fib 1
fib 0 fib 1 fib 0 fib 1
wiederholte Berechnungen der fib-Funktion
Prof. Dr. Margarita Esponda
fib 1 fib 2
fib 0 fib 1
Berechnung der Fibonacci-Zahlen
Beispiel:
fib 7
fib 7
fib 5
fib 3
fib 1
fib 0
fib 4
fib 2
fib 1
fib 6
fib 2
fib 4
fib 3
fib 2
fib 5
fib 3
fib 3
fib 4
fib 0 fib 1 fib 1 fib 2 fib 0 fib 1 fib 1 fib 2 fib 1 fib 2 fib 2 fib 3
fib 0 fib 1
Fallgrube
Wenn wir fib 40 mit unserer
rekursiven Implementierung
berechnen,
wird:
fib 0 fib 1 fib 0 fib 1
fib 39 einmal berechnet
fib 38 2 mal berechnet
fib 1 fib 2
fib 0 fib 1
fib 37 3 mal berechnet
fib 36 5 mal berechnet
fib 35 8 mal berechnet
...
fib 0 165 580 141 mal berechnet
Beim Aufruf von fib 40 werden 331 160 281 Funktionsaufrufe gemacht
Funktionale Programmierung
Berechnung der Fibonacci-Zahlen
Wie viele Reduktionsschritte brauchen wir, um fib n zu berechnen?
fib 0
1
fib 1
+
1
1
=
+
fib 2
2
2
2
fib 3 fib 4
5
3
=
+
fib 5
fib 6
8
13
Reduktionen
3
3
3
=
+
5
5
3
=
+
8
5
=
13
Die Anzahl der Reduktionen für fib n ist gleich fib (n+1)
Die Anzahl der rekursive Aufrufe ist eine
exponentielle Funktion von n.
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Berechnung der Fibonacci-Zahlen
2. Lösung
quickFib funktioniert nur, wenn diese mit
den ersten zwei Fibonacci-Zahlen
gestartet wird.
fib' n = quickFib 0 1 n
Zähler
where
quickFib a b 0 = a
quickFib a b n = quickFib b (a+b) (n-1)
Innerhalb jedes rekursiven Aufrufs wird eine neue Fibonacci-Zahl berechnet und
der Zähler verkleinert. Die neue Zahl und ihr Vorgänger werden beim nächsten
rekursiven Aufruf als Parameter weitergegeben.
Anzahl der Reduktionen
Für die Berechnung von quickFib n benötigen wir n Reduktionen,
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Fibonacci-Zahlen
3. Lösung mit Tupeln:
nextFib :: (Integer, Integer) -> (Integer, Integer)
nextFib (a,b) = (b, a+b)
fib n = fst ( fibTuple n ) Text
fibTuple n | n==0
= (0, 1)
| otherwise = nextFib (fibTuple (n-1))
Prof. Dr. Margarita Esponda
25
Funktionale Programmierung
Listen
Listen sind die wichtigsten Datenstrukturen in funktionalen
Programmiersprachen
Listen stellen Sammlungen von Objekten dar, die den gleichen
Datentyp besitzen
Listen sind dynamische Datenstrukturen, die mit Hilfe folgender
Daten-Konstruktoren erzeugt werden können
Symbol
Prof. Dr. Margarita Esponda
Name
Bedeutung
[]
nil
leere Liste
(:)
cons
am Anfang anfügen
Funktionale Programmierung
Listen
Listen sind rekursive Strukturen:
Eine Liste ist entweder leer
[]
oder ein konstruierter Wert, der aus einem Listenkopf x
und einer Restliste xs besteht.
head
tail
x : xs
Der Typ einer Liste, die Elemente des Typs t enthält, wird
mit [t] bezeichnet.
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Ausdrücke mit Listen
Beispiele:
Ausdruck
Datentyp
[1, 2, 3]
::
[Integer]
1: [0,3,7]
::
[Integer]
[ [0.3, 0.0], [] ]
::
[[Double]]
'a' : "Hello"
::
[Char]
[( 3, 0 ), ( 2, 1)]
::
[ (Integer, Integer) ]
[ True, True, False ]
::
[ Bool ]
Allgemeine Syntax:
[ e1, e2, e3, … ,en ]
Prof. Dr. Margarita Esponda
Syntaktische Abkürzung:
e1:[e2:[e3: … :en:[]]]
e1:e2: … :en:[]
Funktionale Programmierung
Ausdrücke mit Listen
Beispiele:
equiv.
[1, 2, 3]
1:[2, 3]
1 : 2 : 3 : []
"hello"
['h', 'e', 'l', 'l', 'o']
'h' : "ello"
Prof. Dr. Margarita Esponda
[( 3, 0 ), ( 2, 1)]
( 3, 0 ) : [( 2, 1)]
[[3, 0 ], [2, 1]]
[3, 0] : [2, 1] : []
Funktionale Programmierung
Funktionen mit Listen
kopf :: [ Integer ] -> Integer
kopf (x:xs) = x
kopf [] = error "ERROR: empty list"
rumpf :: [ Integer ] -> [ Integer ]
rumpf (x:xs) = xs
rumpf [] = error "ERROR: empty list"
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen mit Listen
Addiert alle Zahlen innerhalb einer Liste
summe :: [Integer] -> Integer
summe
ls
=
if
ls == []
then
0
else ( kopf ls ) + summe (rumpf ls)
Lösung mit Pattern-Matching über der Listenstruktur
summe :: [Integer] -> Integer
summe
[]
summe
(x : xs) =
Prof. Dr. Margarita Esponda
=
0
x + summe xs
Funktionale Programmierung
Funktionsdefinitionen mit Listen
multList :: [Integer] -> Integer
multList [] = error "the function is not defined for []"
multList [x] = x
multList (x:xs) = x * multList xs
laenge :: [Int] -> Int
laenge [] = 0
laenge (x:xs) = 1 + laenge xs
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Zehnersystem → Binärsystem
42 10
=
div 2 mod 2
101010 2
42
0
21
1
10
0
5
1
2
1
0
0
1
dec2bin :: Int -> [Int]
dec2bin
n | n<2
= [n]
| otherwise = dec2bin (n`div`2) ++ [n `mod`2]
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen mit Listen
Verkettungsoperator
drehe [] = []
drehe (x:xs) = drehe xs ++ [x]
drehe [1,2,3] ⇒ drehe [2,3] ++ [1]
⇒ drehe [3] ++ [2] ++ [1]
⇒ drehe [] ++ [3] ++ [2] ++ [1]
⇒ [] ++ [3] ++ [2] ++ [1]
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen mit Listen
1011012 = 1*25 + 0*24 + 1*23 + 1*22 + 0*21 + 1*20
= 2(2(2(2(2(1)+0)+1)+1)+0)+1
binary2decimal xs = bin2dec ( drehe xs)
bin2dec :: [Int] -> Int
bin2dec [] = 0
bin2dec (x:xs) = x + 2*(bin2dec xs)
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen mit Listen
bitXOr :: [Int] -> [Int] -> [Int]
bitXOr [] [] = []
bitXOr (x:xs) (y:ys) = (exoder x y): (bitXOr xs ys)
bitXOr _ _ = error "the two lists are not of the same length"
exoder :: Int -> Int -> Int
exoder x y | x==y
=0
| otherwise = 1
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionstypen
Funktionen haben in Haskell einen Datentyp, der folgende
allgemeine Form hat:
func :: T1 -> T2 ,
wobei
T1, T2 wiederum beliebige Datentypen sind
Beispiel:
func :: (Char, Bool, [Int]) -> Bool -> Int
add :: Integer -> Integer -> Integer
add x y =
Prof. Dr. Margarita Esponda
x+y
Funktionale Programmierung
Funktionstypen
Die Funktionsapplikation ist linksassoziativ
Der Wert dieses Ausdrucks ist wiederum
eine Funktion, die die Zahl 3 zum
eingegebenen Argument addiert.
add 3 7
wird als
(add 3) 7
interpretiert
Der Datentyp der Funktion ist dagegen rechtsassoziativ
Funktionstyp nach der partiellen
Auswertung der Funktion,
add :: Integer -> (Integer -> Integer)
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Currying
In Haskell kann eine Funktion, die zwei oder mehr Argumente
erwartet, als eine Verschachtelung von Funktionen interpretiert
werden, die jeweils nur ein Argument bekommen ( implizites
Currying).
Beispiel:
mult :: Int -> Int -> Int
mult x y = x * y
Die mult-Funktion ist curryfiziert!
Diese Definition ermöglicht eine partielle Anwendung wie z.B.
sum 1, die als Ergebnis eine Funktion zurückgibt, die ein zweites
Argument erwartet.
inc :: Int -> Int
inc = (sum 1)
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionstypen
Eine nicht curryfizierte Definition der add-Funktion sieht wie
folgt aus:
add2 :: (Integer , Integer) -> Integer
Eine partielle Auswertung mit nur einem
Argument ist nicht möglich, weil beide
Argumente, als Tupel verpackt,
eingegeben werden müssen.
Anwendungsbeispiel:
add2 ( 3, 4 )
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Polymorphe Datentypen
Die Angabe eines genauen Typs für ein Argument oder einen
Ausdruck ist oft nicht möglich oder wünschenswert.
typisches Beispiel:
length []
=0
length x:xs = 1 + length xs
Dann verwendet man einen allgemeineren polymorphen Typ
length
:: [a] -> Integer
Eine Funktion, die variable Datentypen beinhaltet, wird als
polymorphe Funktion bezeichnet.
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Polymorphe Funktionen
Beispiele:
head :: [a] -> a
head (x:xs) = x
tail:: [a] -> [a]
tail (x:xs) = xs
take :: Int -> [a] -> [a]
drop:: Int -> [a] -> [a]
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Einige vordefinierte Funktionen auf Listen
Name
Typ
Beispiel
head
[a] -> a
head [1,2,3] => 1
tail
[a] -> [a]
tail [1,2,3] => [2,3]
length
[a] -> Int
length [1,2,3] => 3
(++)
[a] -> [a] -> [a]
[1,2,3] ++ [1,2,3] => [1,2,3,1,2,3]
(!!)
[a] -> Int -> a
[1,2,3,4] !! 2 => 3
take
Int -> [a] -> [a]
take 2 [1,2,3,4] => [1,2]
drop
Int -> [a] -> [a]
drop 2 [1,2,3,4] => [3,4]
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Strings
Strings sind Listen von Zeichen
Typ-Synonym
type String = [Char]
Syntaktische Abkürzung
[ 'H' , 'e', 'l', 'l', 'o' ]
=>
"Hello"
Haskell ruft implizit am Ende der Auswertung eines Ausdrucks die ShowFunktion an, die aus einem beliebigen Datentyp ein String erzeugt.
…
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Strings
Strings sind Listen von Zeichen
Typ-Synonym
type String = [Char]
Syntaktische Abkürzung
[ 'H' , 'e', 'l', 'l', 'o' ]
=>
"Hello"
Haskell ruft implizit am Ende der Auswertung eines Ausdrucks die ShowFunktion an, die aus einem beliebigen Datentyp ein String erzeugt.
…
Prof. Dr. Margarita Esponda
Herunterladen