Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Algorithmen und Datenstrukturen – Einführung Weitere Aspekte von Funktionen in Haskell D. Rösner Institut für Wissens- und Sprachverarbeitung Fakultät für Informatik Otto-von-Guericke Universität Magdeburg Winter 2008/2009, 6. November 2008 D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Gliederung 1 Funktionen 2 . . . höherer Ordnung 3 Abstraktion 4 . . . als Wert D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen in Haskell: Funktionen sind in funktionalen Programmiersprachen ‘Bürger erster Klasse’ (‘first class citizens’) sie unterscheiden sich nicht von (anderen) Daten, sie können Argumente von Funktionen sein, sie können Werte von Funktionen sein, sie können Elemente in zusammengesetzten Datenstrukturen sein (z.B. Listen, Tupel, . . . ). D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Operationen mit Funktionen Definition von Funktionen Anwendung von Funktionen auf Argumente (Funktionsapplikation) Argumente können verschachtelt wieder Anwendungen von Funktionen auf Argumente sein partielle Anwendung von Funktionen Funktionskomposition D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Definition von Funktionen Definition von Funktionen mit Gleichungen dabei bedingte Ausdrücke verwendbar Beispiel max :: Int -> Int -> Int max x y = if x >= y then x else y gegebenenfalls verschachtelte bedingte Ausdrücke Beispiel fib :: Int -> Int fib x = if x == 0 then 0 else if x == 1 then 1 else fib (x - 1) + fib (x - 2) D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Definition von Funktionen cont. Variante mit ‘Wächtern’ (engl. ‘guards’) boolesche Ausdrücke für Fälle in einer Definition idealerweise disjunkt und vollständig abdeckend Beispiel max :: Int -> Int -> Int max x y | x >= y | otherwise = x = y D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Definition von Funktionen cont. Beispiele cont.: Beispiel fib fib | | | :: Int -> Int x x == 0 = 0 x == 1 = 1 x > 1 = fib (x - 1) + fib (x - 2) Variante: Beispiel fib x | x == 0 || x == 1 | otherwise = x = fib (x - 1) + fib (x - 2) D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Definition von Funktionen cont. Variante mit ‘Pattern matching’ Beispiel fib :: Int -> Int fib 0 = 0 fib 1 = 1 fib x = fib (x - 1) + fib (x - 2) Beachte: Fakt ‘guards’ bzw. Gleichungen werden sequentiell (von oben nach unten) ausgewertet D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Definition von Funktionen cont. anonyme Variable (wildcards) beim ‘Pattern matching’ Beispiel mistery :: Int -> Int -> Int mistery 0 y = y mistery x y = x mit ‘wildcards’: Beispiel mistery :: Int -> Int -> Int mistery 0 y = y mistery x _ = x D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Definition von Funktionen cont. ‘wildcards’ immer dann sinnvoll, wenn beliebige Werte im Muster (auf der linken Seite) zugelassen werden sollen und auf diese auf der rechten Seite der Gleichung nicht verwiesen werden muss D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Definition von Funktionen cont. Funktionsdefinitionen können wechselseitig aufeinander Bezug nehmen Beispiel isEven, isOdd :: Int -> Bool isEven 0 = True isEven 1 = False isEven n = isOdd (n-1) isOdd 0 = False isOdd 1 = True isOdd n = isEven (n-1) D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Definition von Funktionen cont. Problem (Warum reichen diese Definitionen nicht?) isEven, isOdd :: Int -> Bool isEven 0 = True isEven n = isOdd (n-1) isOdd 1 = True isOdd n = isEven (n-1) D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen höherer Ordnung: Definition Funktionen sind Funktionen höherer Ordnung, wenn sie eine Funktion als Argument nehmen und/oder eine Funktion als Wert zurückgeben. Funktionen höherer Ordnung (auch Funktionale genannt) dienen der Abstraktion. Wiederkehrende Programmiermuster (pattern) lassen sich häufig als Funktionen höherer Ordnung darstellen. D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen höherer Ordnung: Beispiele wiederkehrender Programmiermuster bei Listen Test, ob alle Elemente einer Liste eine Bedingung erfüllen Test, ob mindestens ein Element einer Liste eine Bedingung erfüllt Auswählen der Elemente einer Liste, die einer Bedingung genügen (und verwerfen der anderen; sog. Filtern) Anwenden einer Funktion auf jedes Element einer Liste und Rückgabe der Liste mit den Resultaten u.v.a.m. D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Programmiermuster ’Gilt Bedingung für alle?’: Programmiermuster: Test, ob alle Elemente einer Liste eine Bedingung erfüllen Fallunterscheidung: Liste ist leer, dann trifft Bedingung zu bei nichtleerer Liste muss der Kopf die Bedingung erfüllen und die Bedingung muss – rekursiv – für alle Elemente des Rests der Liste zutreffen D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Programmiermuster ’Gilt Bedingung für alle?’: Realisierung als Funktion all mit erstes Argument: Bedingung als Prädikat pred, d.h. als Funktion vom Typ a -> Bool für bel. Typ a zweites Argument: zu testende Liste mit Elementen vom Typ a in Haskell (s.a. Prelude.hs): Beispiel all :: (a -> Bool) -> [a] -> Bool all pred [] = True all pred (x:xs) = pred x && all pred xs D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Programmiermuster ’Bedingung für mind. ein Element erfüllt?’: Programmiermuster: Test, ob mind. ein Element einer Liste eine Bedingung erfüllt Fallunterscheidung: Liste ist leer, dann gibt es kein Element, welches Bedingung erfüllt bei nichtleerer Liste muss entweder Kopf die Bedingung erfüllen oder die Bedingung muss – rekursiv – für mind. ein Element des Rests der Liste zutreffen D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Programmiermuster ’Bedingung für mind. ein Element erfüllt?’: Realisierung als Funktion any mit erstes Argument: Bedingung als Prädikat pred, d.h. als Funktion vom Typ a -> Bool für bel. Typ a zweites Argument: zu testende Liste mit Elementen vom Typ a in Haskell (s.a. Prelude.hs): Beispiel any :: (a -> Bool) -> [a] -> Bool any pred [] = False any pred (x:xs) = pred x || any pred xs D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Programmiermuster Filtern: Wiederkehrende Frage und Aufgabe: welche Elemente einer Liste genügen einer gewünschten Eigenschaft? Wähle diese aus und verwerfe die anderen. wiederum: Darstellung von Eigenschaften als Prädikate, d.h. als Funktionen vom Typ t -> Bool für bel. Typ t Funktion filter nimmt ein Prädikat und eine Liste als Argument und gibt die Liste derjenigen Elemente zurück, für die das Prädikat zutrifft mögliche Definition direkt: Beispiel filter p [] = [] filter p (x:xs) = if p x then x:(filter p xs) else filter p xs D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Programmiermuster Filtern: mögliche Definition als Listenkomprehension: Beispiel filter p xs = [x | x <- xs, p x] Typ von filter?: filter :: ( a -> Bool) -> [a] -> [a] D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Die Funktion map Programmiermuster: Anwendung einer Funktion auf jedes Element einer Liste; Ergebnis ist die Liste der Funktionswerte zu den Elementen mögliche Definitionen: direkt: Beispiel map f [] = [] map f (x:xs) = f x : (map f xs) als Listenkomprehension: Beispiel map f xs = [ f x | x <- xs] D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Die Funktion map cont. Typ von map? map :: (a -> b) -> [a] -> [b] Beispiele für Anwendung: Beispiel doubleAll xs = map double xs double x = 2 * x Beispiel convertChrs :: [Char] -> [Int] convertChrs xs = map ord xs D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Elementweises Verbinden von Listen: zip zip: aus zwei Listen (d.h. Paar von Listen) mache Liste mit Paaren korrespondierender Elemente; ignoriere „überschüssige“ Elemente ohne korrespondierenden Partner Definition (direkt; s.a. Prelude.hs) zip :: [a] -> [b] -> [(a,b)] zip [] _ = [] zip _ [] = [] zip (x:xs) (y:ys) = (x,y):(zip xs ys) Beispiel: zip [4,7,1,1] "Koeln" = [(4,’K’),(7,’o’),(1,’e’),(1,’l’)] D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Elementweises Verbinden von Listen: zipWith Verallgemeinerung zipWith: verknüpfe die korrespondierenden Elemente mit einer zweistelligen Funktion zipWith f (x:xs) (y:ys) = f x y : (zipWith f xs ys) zipWith f _ _ = [] Beispiel: zip [1 .. 4] [2,4,6,8] ==> ... ? zipWith (+) [1 .. 4] [2,4,6,8] ==> ... ? Typ von zipWith? : zipWith :: ................................... D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Anonyme Funktionen Funktionen als Argumente von Funktionen höherer Ordnung können einerseits durch ihren Namen referenziert werden wird eine Funktion nur als Argument bei einer Anwendung einer Funktion höherer Ordnung benötigt (und nirgends sonst), so reicht oft auch eine sog. anonyme Funktion aus die Darstellung anonymer Funktionen erfolgt durch einen Lambda-Ausdruck mit der Syntax: (\<var(s)> -> <körper>) Syntax in Anlehnung an den sog. λ-Kalkül mit (λxy .x ∗ x + y ) D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Anonyme Funktionen Beispiele anonymer Funktionen: Beispiel (\x -> x*x) Beispiel (\x y -> x*x - 2*x*y + y*y) Beispiel (Variante) (\x -> (\y -> x*x - 2*x*y + y*y)) Beachte: anonyme Funktionen sind wie benannte Funktionen verwendbar D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionale Abstraktion: Beispiele rekursiv definierter Funktionen (vgl. [RL99], 1.2.2) Fakultätsfunktion fact n | n == 0 = 1 | n > 0 = n * fact(n-1) Summe der natürlichen Zahlen bis n sumInt n | n == 0 = 0 | n > 0 = n + sumInt(n-1) Summe der Quadrate der natürlichen Zahlen bis n sumSqr n | n == 0 = 0 | n > 0 = n*n + sumSqr(n-1) D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Beispiele . . . cont. das den obigen Beispielen zugrundeliegende Rekursionsprinzip kann wie folgt abstrahiert werden: es wird Funktionswert für die Basis (d.h. für n == 0) definiert der Funktionswert für n ergibt sich durch Kombination von n (bzw. eines aus n berechneten Werts) mit dem Funktionswert für (n-1) m.a.W.: der Rekursionsschritt wird als Anwendung einer zweistelligen Kombinationsfunktion auf n und Funktionswert für (n-1) realisiert s.a. [RL99], 1.2.2 D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Darstellung dieser Abstraktion in Haskell mögliche Definition als Funktion höherer Ordnung Definition induction base comb n | n == 0 = base | n > 0 = comb n (induction base comb (n-1)) Problem Was ist der Typ von induction ? Lösung induction :: . . . s.a. [RL99], 1.2.2 D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Abstraktion: induction induction ist Funktion höherer Ordnung (nimmt eine Funktion als Argument; hier: comb) damit Darstellung von fact bzw. sumInt mit Hilfe von induction und der vordefinierten Funktionen (+) bzw. (*) > fact n = induction 1 (*) n > sumInt n = induction 0 (+) n D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Abstraktion: induction alternativ: Definition auf Funktionsebene möglich, d.h. > fact = induction 1 (*) > sumInt = induction 0 (+) die rechten Seiten dieser Gleichungen zeigen sog. partielle Anwendungen von mehrstelligen Funktionen D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Benannte vs. anonyme Funktionen die Kombinationsfunktion für sumSqr könnte benannt definiert werden, z.B. f x y = x*x + y dann: > sumSqr n = induction 0 f n bzw. > sumSqr = induction 0 f D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Benannte vs. anonyme Funktionen alternativ: Kombinationsfunktion als sog. anonyme Funktion sumSqr n = induction 0 (\x y -> x*x + y) n bzw. sumSqr = induction 0 (\x y -> x*x + y) D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen als Werte: Beispiel: Funktionen zur Manipulation beliebiger reeller Funktionen (vgl. [PH06], 1.2, p. 24) Sei f :: Float -> Float beliebig. Dann: shift :: Float -> (Float -> Float) -> (Float -> Float) shift dx f x = f (x - dx) mirror :: (Float -> Float) -> (Float -> Float) mirror f x = f (-x) stretch :: Float -> (Float -> Float) -> (Float -> Float) stretch r f x = f (x/r) Frage: Wie wirken sich shift, mirror und stretch aus? D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionskomposition Verknüpfung von Funktionen als Kontrollstruktur: Ausgabe einer Funktion wird Eingabe der nachfolgenden Definition: (f . g) x = f ( g x ) f . g bedeutet: wende zuerst g, dann f an m.a.W. Verknüpfung muss von rechts nach links gelesen werden als ‘g, dann f’ D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionskomposition Typ von ‘.‘: (.) :: (b -> c) -> (a -> b) -> (a -> c) Funktionskomposition ist assoziativ, d.h. für alle f, g und h f . (g . h) = (f . g) . h in Haskell aus technischen Gründen als rechtsassoziativ behandelt; d.h. f . g . h = f . (g . h) D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Beispiel Funktionskomposition: eine Funktion zweimal anwenden eine Funktion zweimal anwenden Beispiel twice :: (a -> a) -> (a -> a) twice f = f . f Sei succ :: Int -> Int succ n = n + 1 Was ergibt dann (twice succ) 7 ==> ... ? D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionskomposition Verallgemeinerung: n-fach wiederholte Funktionsanwendung Beispiel iter :: Int -> (a -> a) -> (a -> a) iter n f | n > 0 |otherwise = f . iter (n-1) f = id Frage: Was ergibt iter n double 1 ==> ... ? D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Partielle Anwendung Beispiel: multiply :: Int -> Int -> Int multiply x y = x * y Frage: was ergibt multiply 2 ==> ... ? D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Partielle Anwendung cont. Beispiel doubleAll :: [Int] -> [Int] doubleAll = map (multiply 2) hier zwei partielle Anwendungen: multiply 2 :: Int -> Int map (multiply 2) :: [Int] -> [Int] Variante ohne partielle Anwendung von map: Beispiel doubleAll xs = map (multiply 2) xs D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Bestimmung des Typs einer partiellen Anwendung Streichungsregel (cancellation rule) (s.a. [Tho99], 10.4): Wenn der Typ einer Funktion f t1 -> t2 -> ...tn -> t ist und diese wird angewendet auf e1 ::t1 , e2 ::t2 , ..., ek ::tk mit (k<=n), dann ergibt sich der Ergebnistyp durch „Streichen“ der Typen t1 bis tk , d.h. der Ergebnistyp von f e1 e2 ...ek ist tk +1 -> tk +2 -> ...tn -> t D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Assoziativität Beachte: Funktionsanwendung ist linksassoziativ, d.h. f x y = (f x) y -> ist rechtsassoziativ, d.h. a -> b -> c entspricht a -> (b -> c) -> ist nicht assoziativ; Beispiel: g :: (Int -> Int) -> Int g h = (h 0) + (h 1) D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen in Haskell Beachte: jede Funktion in Haskell nimmt exakt ein Argument So bedeutet multiply :: Int -> Int -> Int wegen der Rechtsassoziativität multiply :: Int -> (Int -> Int) Damit multiply 2 :: Int -> Int und (multiply 2) 5 :: Int D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen in Haskell Allgemein (s.a. [Tho99], 10.4): f e1 e2 ...ek bzw. t1 -> t2 -> ...tn -> t sind Abkürzungen für (...((f e1 ) e2 ) ...ek ) bzw. t1 -> (t2 -> (...(tn -> t) ...)) D. Rösner AuD 2008/2009 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Literatur (Auswahl): Peter Pepper and Petra Hofstedt. Funktionale Programmierung – Sprachdesign und Programmiertechnik. Springer, Heidelberg, 2006. ISBN-10 3-540-20959-X; ISBN-13 978-3-540-20959-1. Fethi Rabhi and Guy Lapalme. Algorthms – A Functional Programming Approach. Pearson Education Ltd., Essex, 1999. 2nd edition, ISBN 0-201-59604-0. Simon Thompson. Haskell - The Craft of Functional Programming. Addison Wesley Longman Ltd., Essex, 1999. 2nd edition, ISBN 0-201-34275-8; Accompanying Web site: http://www.cs.ukc.ac.uk/people/staff/sjt/craft2e. D. Rösner AuD 2008/2009 . . .