Funktionen höherer Ordnung

Werbung
Funktionale Programmierung
ALP I
Funktionen höherer Ordnung
SS 2011
Prof. Dr. Margarita Esponda
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionstypen
Funktionen haben einen Datentyp, der folgende allgemeine
Form hat:
functionname :: T1 -> T2 ,
wobei
Beispiel:
T1, T2 wiederum beliebige Datentypen sind
T2
T1
Der Datentyp einer
Funktion ist
rechtsassoziativ.
( Integer -> Integer )
add x y = ((+) x ) y
add :: Integer
->
Die Funktionsapplikation
dagegen ist linksassoziativ.
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Currying
Eine Funktion mit mehr als einem Argument kann als eine
Verschachtelung von Funktionen interpretiert werden, in der jede
Funktion nur ein Argument bekommt.
Haskell hat implizites Currying!
Beispiel:
mult :: Int → ( Int → ( Int → Int ) )
mult x y z = x * y * z
mult a b c
=> ( mult a ) b c
=> ((mult a ) b) c
Die mult-Funktion ist curryfiziert!
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Currying
f :: t1 → t 2 → ... t n
t1
t2
t3
..
.
t n −1
Prof. Dr. Margarita Esponda
f
( f t1 )
t1
..t 2
.
t n −1
f
tn
( ( f t1 ) t 2 )
(..(( ft1 ) t 2 ).. t n −1 )
tn
Funktionale Programmierung
Funktionstypen
Eine nicht curryfizierte Definition der mult-Funktion sieht wie folgt aus:
mult :: (Integer, 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:
mult (3, 4, 2)
Prof. Dr. Margarita Esponda
⇒
24
Funktionale Programmierung
Sektionen
Jede arithmetische Infix-Operation kann in eine Curried-Funktion
verwandelt werden, indem der Operator in runden Klammern und
als Präfix-Funktion geschrieben wird.
Beispiel:
(+) 3 4
dann sieht eine partielle Auswertung der Funktion wie folgt aus:
(+ 3) 4
Funktion, die zu einem beliebigen Argument die Zahl 3 addiert
Im allgemeinen, wenn ⊕ ein Infix-Operator ist, werden Ausdrücke
mit der Form (⊕ x) oder (x ⊕) Sektionen genannt.
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen höherer Ordnung
Eine Funktion wird als Funktion höherer Ordnung
bezeichnet, wenn Funktionen als Argumente verwendet
werden oder wenn eine Funktion als Ergebnis zurück
gegeben wird.
Beispiel:
twoTimes :: ( a -> a ) -> a -> a
twoTimes f x = f ( f x )
Anwendung:
twoTimes quadrat 3 => quadrat (quadrat 3) => 81
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen höherer Ordnung
Typische Beispielsfunktion:
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : map f xs
map f
[2, 3, 6, 0]
=> [f(2), f(3), f(6), f(0)]
Die Funktion f wird auf jedes Element der Liste angewendet
map (^2) [2, 3, 6, 0]
Prof. Dr. Margarita Esponda
=> [4, 9, 36, 0]
Funktionale Programmierung
Funktionen höherer Ordnung
Eine andere Definition der map-Funktion mit
Listen-Generatoren ist:
map :: (a -> b) -> [a] -> [b]
map f xs = [ f x | x<-xs ]
Anwendung:
map length ["Eins", "Zwei", "Drei", "Vier"] => [4, 4, 4, 4]
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen höherer Ordnung
Die filter-Funktion
Die filter-Funktion soll aus einer Liste nur die
Elemente auswählen, die eine bestimmte Bedingung
erfüllen.
Beispiel:
filter (<3) [2,5,0,1,7]
Prof. Dr. Margarita Esponda
=>
[2,0,1]
Funktionale Programmierung
Funktionen höherer Ordnung
Die filter-Funktion
1. Definition:
filter :: (a -> Bool) -> [a] -> [a]
filter p [] = []
filter p (x:xs)
Bedingung
|p x
= x : filter p xs
| otherwise = filter p xs
2. Definition:
filter :: (a -> Bool) -> [a] -> [a]
filter p xs = [ x | x <- xs, p x ]
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen höherer Ordnung
Die filter-Funktion
Beispiel:
Quicksort-Algorithmus mit Hilfe der filter-Funktion
qsort :: (Ord a) => (a -> a -> Bool) -> [a] -> [a]
qsort p [] = []
qsort p [x] = [x]
qsort p (x:xs) = qsort p (filter (p x) xs) ++ [x] ++ qsort p (filter (np x) xs)
where
np x y = not (p x y)
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen höherer Ordnung
Nehmen wir an, wir möchten alle Zahlen innerhalb einer
Liste miteinander addieren
addAll:: (Num a) => [a] -> a
addAll [] = 0
addAll (x:xs) = x + addAll xs
oder die Und-Operation über alle Elemente einer Liste
berechnen
trueAll:: [Bool] -> Bool
trueAll [] = True
trueAll (x:xs) = x && (trueAll xs)
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen höherer Ordnung
Gemeinsamkeiten von beiden Funktionen sind:
- Binär-Operator
- konstanter Wert, wenn die Liste leer ist.
- gleiches Rekursions-Muster
Wir können eine verallgemeinerte Funktion definieren, die
beide Probleme löst
Verallgemeinerungen sind immer gut!
Beispiel:
trueAll = betweenAll (&&) True
addAll
= betweenAll (+) 0
multAll = betweenAll (*) 1
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen
höherer Ordnung
Verallgemeinerungen sind immer gut!
betweenAll :: (a -> a -> a) -> a -> [a] -> a
Binäre Operation
Wert der Funktion,
wenn die Liste leer ist
betweenAll f
k [] = k
betweenAll f
k (x:xs) = f x (betweenAll f k xs)
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen höherer Ordnung
foldr-Funktion
In Haskell ist bereits eine allgemeine Funktion vordefiniert,
die Faltungs-Operator genannt wird
Definition:
foldr f z []
=z
foldr f z (x:xs) = f x (foldr f z xs)
foldr (*) 1 [1,2,3,4]
:
1
1
:
2
3
2
*
3
:
4
Prof. Dr. Margarita Esponda
=>
:
*
[]
=>
*
4
*
1
24
Funktionale Programmierung
Funktionen höherer Ordnung
foldr-Funktion
Haskell:
foldr :: (a → b → b) → b → [a] → b
foldr f z []
=z
foldr f z (x:xs) = f x (foldr f z xs)
Beispiel:
len :: [a] → Int
len xs = foldr onePlus 0 xs
where
onePlus :: a → Int → Int
onePlus x n = 1 + n
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen höherer Ordnung
Folgende Standard-Funktionen von Haskell können
mit Hilfe des Faltungs-Operators definiert werden:
Beispiele:
Prof. Dr. Margarita Esponda
sum
= foldr (+) 0
product
= foldr (*) 1
or
= foldr (||) False
and
= foldr (&&) True
Funktionale Programmierung
Funktionen höherer Ordnung
foldl-Funktion
foldl :: (b → a → b) → b → [a] → b
Definition:
foldl f z []
=z
foldl f z (x:xs) = foldl f (f z x) xs
foldl f k [8,6,4,2]
f
:
8
:
6
f
:
2
Prof. Dr. Margarita Esponda
=>
:
4
f
f
[]
k
4
6
8
2
Funktionale Programmierung
Beispiele:
Faltungs-Operatoren
foldr (*) 1 [1..5]
=>
120
Fakultät-Funktion
factorial n = foldr (*) 1 [1..n]
Potenz-Funktion für positive ganzzahlige Potenzen
pow b n
= foldl (*) 1 (take n [b,b..b])
foldr max 0 [-6,3,6,12,14,0,23]?
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen höherer Ordnung
zip-Funktion
zip (x:xs) (y:ys)
= (x,y) : zip xs ys
zip xs
= []
ys
Die zip-Funktion kombiniert die Elemente aus zwei
Listen und liefert eine Liste von Tupeln zurück.
Beispiel:
zip [1..] ["abcd"] ⇒ [(1,'a'), (2,'b'), (3,'c'), (4,'d')]
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen höherer Ordnung
zipWith-Funktion
Die zipWith-Funktion bekommt zwei Listen und eine
Funktion als Parameter und berechnet eine neue Liste,
indem jeweils die Elemente der beiden Listen mit der
angegebenen Funktion verknüpft werden.
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f (x:xs) (y:ys) = (f x y):(zipWith f xs ys )
zipWith f _ _ = []
Beispiel:
zipWith (^) [1, 2, 3] [0, 3, 2]
Prof. Dr. Margarita Esponda
⇒
[1, 8, 9]
Funktionale Programmierung
Funktionen höherer Ordnung
Anwendungsbeispiel der zipWith-Funktion:
Skalar-Produkt von zwei Vektoren
v1 . v2
v1 = (x1, x2, .. , xn)
v2 = (y1, y2, .. , yn)
ist
v1 . v2 = x1. y1 + x2 . y2 + .. + xn. yn
skalarProd ::[Int] -> [Int] -> Int
skalarProd xs ys
Prof. Dr. Margarita Esponda
= foldl (+) 0 (zipWith (*) xs ys)
Funktionale Programmierung
Funktionen höherer Ordnung
Funktionskomposition
A
g
B
f
f
°g
(.) :: (b → c) → (a → b) → (a → c)
(.) f g x = f (g x)
(f . g) x = f (g x)
Prof. Dr. Margarita Esponda
C
Funktionale Programmierung
Funktionskomposition
Beispiele:
ungerade x = (not . gerade) x
ungerade = not . gerade
Anwendung:
ungerade 4 ⇒ (not . gerade) 4
⇒ not (gerade 4)
⇒ not True
⇒ False
Prof. Dr. Margarita Esponda
equiv.
Funktionale Programmierung
Funktionskomposition
Beispiele:
twoTimes f = f . f
Anwendung:
ungerade 4 ⇒ (not . gerade) 4
⇒ not (gerade 4)
⇒ not True
⇒ False
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionskomposition
Beispiele:
rep f n
| n<0
= error "rep is not defined for n<0"
| n>0
= f . (rep f (n-1))
| n==0 = id
where
id x = x
Anwendung:
rep not 3 True ⇒ not (rep not 2 True)
⇒ not (not (rep not 1 True))
⇒ not (not (not (rep not 0 True)))
⇒ not (not (not (id True)))
⇒ not (not (not (True)))
⇒ False
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen höherer Ordnung
all-Funktion
Entscheidet, ob alle Elemente einer Liste eine
gegebene Bedingung erfüllen.
all :: (a → Bool) → [a] → Bool
all p xs = and [p x | x ← xs]
Beispiel:
all even [2 ,4 ,6 ,8]
all (==3)
Prof. Dr. Margarita Esponda
=> True
[3,4,3,0,3] => False
Funktionale Programmierung
Funktionen höherer Ordnung
any-Funktion
Entscheidet, ob mindestens ein Element einer Liste
eine gegebene Bedingung erfüllt.
any :: (a → Bool) → [a] → Bool
any p xs = or [p x | x ← xs]
Beispiel:
any even [2 ,3 ,6 ,8]
=> True
any (==3) [3,4 ,3 ,0 ,3] => True
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen höherer Ordnung
Wir können einen allgemeineren Quicksort-Algorithmus
definieren, in dem die Vergleichsoperation angegeben wird.
qsort v [] = []
qsort v [x] = [x]
qsort v (x:xs) = qsort v [s|s<-xs, v s x]++[x]++qsort v [b|b<-xs, not (v b x)]
Anwendungsbeispiel:
qsort (<) [3,2,1, 5,4]
Prof. Dr. Margarita Esponda
oder
qsort (>=) [3,2,1, 5,4]
Funktionale Programmierung
Funktionen höherer Ordnung
takeWhile-Funktion
So lange eine Bedingung erfüllt wird, werden Elemente aus
einer Liste genommen.
takeWhile :: (a → Bool) → [a] → [a]
takeWhile p [] = []
takeWhile p (x:xs)
| p x = x : takeWhile p xs
| otherwise = []
Beispiel:
takeWhile (<9)
Prof. Dr. Margarita Esponda
[2, 5, 7, 9, 11]
=>
[2, 5, 7]
Funktionale Programmierung
Funktionen höherer Ordnung
dropWhile-Funktion
So lange eine Bedingung erfüllt wird, werden Elemente aus
einer Liste gelöscht.
dropWhile :: (a → Bool) → [a] → [a]
dropWhile p [] = []
dropWhile p (x:xs)
| p x = dropWhile p xs
| otherwise = x:xs
Beispiel:
dropWhile
Prof. Dr. Margarita Esponda
isSpace
"
Hello"
=>
"Hello"
Funktionale Programmierung
Berechnung der Fibonacci-Zahlen
rekursiv:
fib 0 = 0
fib 1 = 1
fib n = fib (n-2) + fib (n-1)
Die rekursive Berechnung der Fibonacci-Zahlen hat
eine exponentielle Komplexität
O((1,618...)n)
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Funktionen höherer Ordnung
Folgende Funktion berechnet die Fibonacci-Zahlen in
linearer Zeit
O(n)
fibs :: [Integer]
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
fibs
tail fibs
zipWith (+)
0:1:1:2:3:5:8:...
1:1:2:3:5:...
1:2:3:5: 8:...
Anwendungsbeispiel:
take 40 fibs
Prof. Dr. Margarita Esponda
Herunterladen