ALP I Funktionen Höherer Ordnung WS 2009/2010 Prof. Dr. Margarita Esponda Prof. Dr. Margarita Esponda 1 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: twice :: ( a -> a ) -> a -> a twice f x = f ( f x ) ) Anwendung: twice quadrat 3 => quadrat (quadrat 3) => 81 Prof. Dr. Margarita Esponda 2 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 3 Funktionen Höherer Ordnung Typische Beispielfunktion: 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] 4 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 5 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] 6 Funktionen Höherer Ordnung Die filter-Funktion 1. Definition: filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x:xs) | p x = x : filter p xs Bedingung | otherwise = filter p xs 2. Definition: filter :: (a -> Bool) -> [a] -> [a] filter p xs = [ x | x <- xs, p x ] Prof. Dr. Margarita Esponda 7 Funktionen Höherer Ordnung Die filter-Funktion Beispiel: Wir können den Quicksort-Algorithmus mit Hilfe der filter-Funktion wie folgt definieren: qsort [] = [] qsort [x] = [x] qsort (x:xs) = qsort( filter (<=x) xs ) ++ [x] ++ qsort( filter (>x) xs ) Prof. Dr. Margarita Esponda 8 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 9 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 Beispiel: trueAll = betweenAll (&&) True addAll = betweenAll (+) 0 multAll = betweenAll (*) 1 Prof. Dr. Margarita Esponda 10 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 11 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 => * [] => 24 * 4 1 12 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 13 Funktionen Höherer Ordnung foldl-Funktion 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 f : 6 4 f [] k 6 4 f : 2 Prof. Dr. Margarita Esponda => : 8 2 14 Faltungs-Operatoren Beispiele: foldr (*) 1 [1..5] => 120 Fakultät-Funktion factorial n = foldr (*) 1 [1..n] Potenz-Funktion für positive ganzzahlige Potenzen pow b e = foldl (*) 1 (take e [b,b..b]) foldr max 0 [-6,3,6,12,14,0,23]? Prof. Dr. Margarita Esponda 15 Funktionen Höherer Ordnung zipWith-Funktion zip (x:xs) (y:ys) zip xs ys = (x,y) : zip xs ys = [] Die zip-Funktion kombiniert die Elemente aus zwei Listen und liefert eine Liste von Tupeln zurück. 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 _ _ = [] Prof. Dr. Margarita Esponda 16 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 x y Prof. Dr. Margarita Esponda = foldl (+) 0 (zipWith (*) x y) 17 Funktionen Höherer Ordnung Funktionskomposition g f A B f C °g (.) :: (b → c) → (a → b) → (a → c) Beispiel: ungerade = not . gerade Prof. Dr. Margarita Esponda 18 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 19 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 20 Funktionen Höherer Ordnung Wir können eine allgemeinere Quicksort-Algorithmus definieren, indem 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] 21 Funktionen Höherer Ordnung takeWhile-Funktion So lange eine Bedingung erfüllt wird, werden Elemente aus eine 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] 22 Funktionen Höhere 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" 23 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 24 Berechnung der Fibonacci-Zahlen Rekursiv f(7) f(5) f(3) f(1) f(2) f(6) f(4) f(2) f(3) f(4) f(2) f(5) f(3) f(3) f(4) f(0)f(1) f(0)f(1) f(1)f(2)f(0)f(1)f(1)f(2)f(1)f(2) f(2)f(3) f(0)f(1) f(0)f(1) f(0)f(1)f(1)f(2) f(0)f(1) Prof. Dr. Margarita Esponda 25 Berechnung der Fibonacci-Zahlen Rekursiv f(7) f(5) f(3) f(1) f(2) f(6) f(4) f(2) f(3) f(4) f(2) f(5) f(3) f(3) f(4) f(0)f(1) f(0)f(1) f(1)f(2)f(0)f(1)f(1)f(2)f(1)f(2) f(2)f(3) f(0)f(1) f(0)f(1)f(0)f(1) f(1)f(2) f(0)f(1) wiederholte Berechnungen Prof. Dr. Margarita Esponda 26 Berechnung der Fibonacci-Zahlen Rekursiv f(7) f(5) f(3) f(1) f(2) f(6) f(4) f(2) f(3) f(4) f(2) f(5) f(3) f(3) f(4) f(0)f(1) f(0)f(1) f(1)f(2)f(0)f(1)f(1)f(2)f(1)f(2) f(2)f(3) f(0)f(1) Fallgrube Wenn wir fib(40) mit unserer rekursiven Implementierung berechnen, wird: f(0)f(1) f(0)f(1) f(1)f(2) fib(39) einmal berechnet f(0)f(1) fib(38) 2 mal berechnet fib(37) 3 mal berechnet fib(36) 5 mal berechnet fib(35) 8 mal berechnet . . . . mal berechnet fib(0) 165 580 141 mal berechnet Beim Aufruf von fib(40) werden 331 160 281 Funktionsaufrufe gemacht Prof. Dr. Margarita Esponda 27 Funktionen Höherer Ordnung Folgende Funktion berechnet die Fibonacci-Zahlen in linearer Zeit O(n) fibs = 0 : 1 : zipWith (+) fibs (tail fibs) fibs 0:1:1:2:3:5:8:... tail fibs 0:1:1:2:3:5:... zipWith (+) 1 : 2 : 3 : 5 : 8 : . . . Anwendungsbeispiel: take 40 fibs Prof. Dr. Margarita Esponda 28