Gliederung Algorithmen und Datenstrukturen I Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen in Haskell D. Rösner Institut für Wissens- und Sprachverarbeitung Fakultät für Informatik Otto-von-Guericke Universität Magdeburg c Winter 2009/10, 5. November 2009, 2009/10 D.Rösner D. Rösner AuD I 2009/10 . . . 1 D. Rösner AuD I 2009/10 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen in Haskell: Operationen mit Funktionen Funktionen sind in funktionalen Programmiersprachen ‘Bürger erster Klasse’ (‘first class citizens’) Definition von Funktionen Anwendung von Funktionen auf Argumente (Funktionsapplikation) sie unterscheiden sich nicht von (anderen) Daten, Argumente können verschachtelt wieder Anwendungen von Funktionen auf Argumente sein sie können Argumente von Funktionen sein, sie können Werte von Funktionen sein, partielle Anwendung von Funktionen sie können Elemente in zusammengesetzten Datenstrukturen sein (z.B. Listen, Tupel, . . . ). D. Rösner AuD I 2009/10 . . . 2 Funktionskomposition 4 D. Rösner AuD I 2009/10 . . . 5 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Definition von Funktionen Definition von Funktionen cont. Definition von Funktionen mit Gleichungen dabei bedingte Ausdrücke verwendbar Variante mit ‘Wächtern’ (engl. ‘guards’) boolesche Ausdrücke für Fälle in einer Definition Beispiel max :: Int -> Int -> Int max x y = if x >= y then x else y idealerweise disjunkt und vollständig abdeckend Beispiel gegebenenfalls verschachtelte bedingte Ausdrücke max :: Int -> Int -> Int 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 I 2009/10 . . . max x y | x >= y | otherwise 6 D. Rösner AuD I 2009/10 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert 7 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Definition von Funktionen cont. Definition von Funktionen cont. Beispiele cont.: Variante mit ‘Pattern matching’ Beispiel Beispiel fib fib | | | fib :: Int -> Int :: Int -> Int x x == 0 = 0 x == 1 = 1 x > 1 = fib (x - 1) + fib (x - 2) fib 0 = 0 fib 1 = 1 fib x = fib (x - 1) + fib (x - 2) Variante: Beachte: Beispiel fib x | x == 0 || x == 1 | otherwise = x = y Fakt ‘guards’ bzw. Gleichungen werden sequentiell (von oben nach unten) ausgewertet = x = fib (x - 1) + fib (x - 2) D. Rösner AuD I 2009/10 . . . 8 D. Rösner AuD I 2009/10 . . . 9 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Definition von Funktionen cont. Definition von Funktionen cont. anonyme Variable (wildcards) beim ‘Pattern matching’ Beispiel mistery :: Int -> Int -> Int ‘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 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 I 2009/10 . . . 10 D. Rösner AuD I 2009/10 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert 11 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Definition von Funktionen cont. Definition von Funktionen cont. Funktionsdefinitionen können wechselseitig aufeinander Bezug nehmen Problem (Warum reichen diese Definitionen nicht?) Beispiel isEven, isOdd :: Int -> Bool isEven, isOdd :: Int -> Bool isEven 0 = True isEven n = isOdd (n-1) isEven 0 = True isEven 1 = False isEven n = isOdd (n-1) isOdd 1 = True isOdd n = isEven (n-1) isOdd 0 = False isOdd 1 = True isOdd n = isEven (n-1) D. Rösner AuD I 2009/10 . . . 12 D. Rösner AuD I 2009/10 . . . 13 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen höherer Ordnung: Funktionen höherer Ordnung: Definition Funktionen sind Funktionen höherer Ordnung, wenn sie Beispiele wiederkehrender Programmiermuster bei Listen Test, ob alle Elemente einer Liste eine Bedingung erfüllen eine Funktion als Argument nehmen und/oder eine Funktion als Wert zurückgeben. 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) Funktionen höherer Ordnung (auch Funktionale genannt) dienen der Abstraktion. Anwenden einer Funktion auf jedes Element einer Liste und Rückgabe der Liste mit den Resultaten Wiederkehrende Programmiermuster (pattern) lassen sich häufig als Funktionen höherer Ordnung darstellen. D. Rösner AuD I 2009/10 . . . u.v.a.m. 15 D. Rösner AuD I 2009/10 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert 16 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Programmiermuster ’Gilt Bedingung für alle?’: 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 Programmiermuster: Test, ob alle Elemente einer Liste eine Bedingung erfüllen Fallunterscheidung: in Haskell (s.a. Prelude.hs): 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 Beispiel all :: (a -> Bool) -> [a] -> Bool all pred [] = True all pred (x:xs) = pred x && all pred xs D. Rösner AuD I 2009/10 . . . 17 D. Rösner AuD I 2009/10 . . . 18 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Programmiermuster ’Bedingung für mind. ein Element erfüllt?’: 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 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 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 I 2009/10 . . . 19 D. Rösner AuD I 2009/10 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert 20 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Programmiermuster Filtern: Programmiermuster Filtern: Wiederkehrende Frage und Aufgabe: welche Elemente einer Liste genügen einer gewünschten Eigenschaft? Wähle diese aus und verwerfe die anderen. mögliche Definition als Listenkomprehension: 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 xs = [x | x <- xs, p x] Typ von filter?: filter :: ( a -> Bool) -> [a] -> [a] Beispiel filter p [] = [] filter p (x:xs) = if p x then x:(filter p xs) else filter p xs D. Rösner AuD I 2009/10 . . . 21 D. Rösner AuD I 2009/10 . . . 22 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Die Funktion map Die Funktion map cont. Programmiermuster: Anwendung einer Funktion auf jedes Element einer Liste; Ergebnis ist die Liste der Funktionswerte zu den Elementen mögliche Definitionen: Typ von map? map :: (a -> b) -> [a] -> [b] Beispiele für Anwendung: Beispiel direkt: doubleAll xs = map double xs Beispiel map f [] = [] map f (x:xs) = f x : (map f xs) double x = 2 * x Beispiel als Listenkomprehension: convertChrs :: [Char] -> [Int] Beispiel convertChrs xs = map ord xs map f xs = [ f x | x <- xs] D. Rösner AuD I 2009/10 . . . 23 D. Rösner AuD I 2009/10 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert 24 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Elementweises Verbinden von Listen: zipWith 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 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 _ _ = [] Definition (direkt; s.a. Prelude.hs) zip :: [a] -> [b] -> [(a,b)] Beispiel: zip [1 .. 4] [2,4,6,8] ==> ... ? zip [] _ = [] zip _ [] = [] zip (x:xs) (y:ys) = (x,y):(zip xs ys) zipWith (+) [1 .. 4] [2,4,6,8] ==> ... ? Typ von zipWith? : Beispiel: zipWith :: zip [4,7,1,1] "Koeln" = [(4,’K’),(7,’o’),(1,’e’),(1,’l’)] D. Rösner AuD I 2009/10 . . . 25 ................................... D. Rösner AuD I 2009/10 . . . 26 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Anonyme Funktionen Anonyme Funktionen Beispiele anonymer Funktionen: Funktionen als Argumente von Funktionen höherer Ordnung können einerseits durch ihren Namen referenziert werden Beispiel (\x -> x*x) 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 Beispiel (\x y -> x*x - 2*x*y + y*y) die Darstellung anonymer Funktionen erfolgt durch einen Lambda-Ausdruck mit der Syntax: (\<var(s)> -> <körper>) Beispiel (Variante) (\x -> (\y -> x*x - 2*x*y + y*y)) Syntax in Anlehnung an den sog. λ-Kalkül mit (λxy .x ∗ x + y ) D. Rösner AuD I 2009/10 . . . Beachte: anonyme Funktionen sind wie benannte Funktionen verwendbar 27 D. Rösner AuD I 2009/10 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionale Abstraktion: Beispiele . . . cont. Beispiele rekursiv definierter Funktionen (vgl. [RL99], 1.2.2) 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 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 I 2009/10 . . . 28 s.a. [RL99], 1.2.2 30 D. Rösner AuD I 2009/10 . . . 31 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Abstraktion: induction Darstellung dieser Abstraktion in Haskell mögliche Definition als Funktion höherer Ordnung Definition 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. (*) induction base comb n | n == 0 = base | n > 0 = comb n (induction base comb (n-1)) Problem Was ist der Typ von induction ? > fact n = induction 1 (*) n > sumInt n = induction 0 (+) n Lösung induction :: . . . s.a. [RL99], 1.2.2 D. Rösner AuD I 2009/10 . . . 32 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert 33 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Abstraktion: induction Benannte vs. anonyme Funktionen die Kombinationsfunktion für sumSqr könnte benannt definiert werden, z.B. f x y = x* x + y dann: 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 I 2009/10 . . . D. Rösner AuD I 2009/10 . . . > sumSqr n = induction 0 f n bzw. > sumSqr = induction 0 f 34 D. Rösner AuD I 2009/10 . . . 35 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Benannte vs. anonyme Funktionen Funktionen als Werte: Beispiel: Funktionen zur Manipulation beliebiger reeller Funktionen (vgl. [PH06], 1.2, p. 24) alternativ: Kombinationsfunktion als sog. anonyme Funktion Sei f :: Float -> Float beliebig. Dann: sumSqr n = induction 0 (\x y -> x*x + y) n shift :: Float -> (Float -> Float) -> (Float -> Float) bzw. shift dx f x = f (x - dx) sumSqr = induction 0 (\x y -> x*x + y) mirror :: (Float -> Float) -> (Float -> Float) mirror f x = f (-x) ... D. Rösner AuD I 2009/10 . . . D. Rösner AuD I 2009/10 . . . 36 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert 38 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen als Werte: Funktionskomposition Beispiel: Funktionen zur Manipulation beliebiger reeller Funktionen (vgl. [PH06], 1.2, p. 24) Verknüpfung von Funktionen als Kontrollstruktur: Ausgabe einer Funktion wird Eingabe der nachfolgenden Definition: ... stretch :: Float -> (Float -> Float) -> (Float -> Float) (f . g) x = f ( g x ) stretch r f x = f (x/r) f . g bedeutet: wende zuerst g, dann f an Frage: m.a.W. Verknüpfung muss von rechts nach links gelesen werden als ‘g, dann f’ Wie wirken sich shift, mirror und stretch aus? ................................ ................................ ................................ D. Rösner AuD I 2009/10 . . . 39 D. Rösner AuD I 2009/10 . . . 40 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionskomposition Beispiel Funktionskomposition: eine Funktion zweimal anwenden eine Funktion zweimal anwenden Typ von ‘.‘: (.) :: (b -> c) -> (a -> b) -> (a -> c) Beispiel Funktionskomposition ist assoziativ, d.h. für alle f, g und h twice :: (a -> a) -> (a -> a) f . (g . h) = (f . g) . h twice f = f . f in Haskell aus technischen Gründen als rechtsassoziativ behandelt; d.h. Sei f . g . h = f . (g . h) succ :: Int -> Int succ n = n + 1 Was ergibt dann (twice succ) 7 ==> ... ? D. Rösner AuD I 2009/10 . . . D. Rösner AuD I 2009/10 . . . 41 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert 42 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionskomposition Partielle Anwendung Verallgemeinerung: n-fach wiederholte Funktionsanwendung Beispiel: Beispiel multiply :: Int -> Int -> Int iter :: Int -> (a -> a) -> (a -> a) multiply x y = x * y iter n f | n > 0 |otherwise = f . iter (n-1) f = id Frage: was ergibt multiply 2 ==> ... ? Frage: Was ergibt iter n double 1 ==> ... ? D. Rösner AuD I 2009/10 . . . 43 D. Rösner AuD I 2009/10 . . . 44 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Partielle Anwendung cont. Bestimmung des Typs einer partiellen Anwendung Beispiel Streichungsregel (cancellation rule) (s.a. [Tho99], 10.4): doubleAll :: [Int] -> [Int] doubleAll = map (multiply 2) Wenn der Typ einer Funktion f t1 -> t2 -> ... -> tn -> t ist hier zwei partielle Anwendungen: und diese wird angewendet auf e1 ::t1 , e2 ::t2 , ..., ek ::tk mit (k<=n), multiply 2 :: Int -> Int map (multiply 2) :: [Int] -> [Int] dann ergibt sich der Ergebnistyp durch „Streichen“ der Typen t1 bis tk , Variante ohne partielle Anwendung von map: Beispiel d.h. der Ergebnistyp von f e1 e2 ... ek ist tk +1 -> tk +2 -> ... tn -> t doubleAll xs = map (multiply 2) xs D. Rösner AuD I 2009/10 . . . D. Rösner AuD I 2009/10 . . . 45 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert 46 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Assoziativität Funktionen in Haskell Beachte: Beachte: jede Funktion in Haskell nimmt exakt ein Argument Funktionsanwendung ist linksassoziativ, d.h. f x y = (f x) y So bedeutet multiply :: Int -> Int -> Int wegen der Rechtsassoziativität multiply :: Int -> (Int -> Int) -> ist rechtsassoziativ, d.h. a -> b -> c entspricht a -> (b -> c) Damit multiply 2 :: Int -> Int und (multiply 2) 5 :: Int -> ist nicht assoziativ; Beispiel: g :: (Int -> Int) -> Int g h = (h 0) + (h 1) D. Rösner AuD I 2009/10 . . . 47 D. Rösner AuD I 2009/10 . . . 48 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Funktionen in Haskell Literatur: I Allgemein (s.a. [Tho99], 10.4): f e1 e2 ... ek bzw. t1 -> t2 -> ... tn -> t Richard Bird. Introduction to functional programming using Haskell. Prentice Hall Europe, 2000. ISBN 0-13-484346-0; 2nd edition. sind Abkürzungen für (...((f e1 ) e2 ) ... ek ) bzw. t1 -> (t2 -> (...(tn -> t) ...)) Manual M. Chakravarty and Gabriele C. Keller. An Introduction to Computing with Haskell. Pearson Education Australia, 2002. ISBN 1 74009 404 2; also available in German translation. D. Rösner AuD I 2009/10 . . . 49 D. Rösner AuD I 2009/10 . . . Funktionen . . . höherer Ordnung Abstraktion . . . als Wert 50 Funktionen . . . höherer Ordnung Abstraktion . . . als Wert Literatur: II Literatur: III 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. 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. Fethi Rabhi and Guy Lapalme. Algorithms – A Functional Programming Approach. Pearson Education Ltd., Essex, 1999. 2nd edition, ISBN 0-201-59604-0. D. Rösner AuD I 2009/10 . . . 51 D. Rösner AuD I 2009/10 . . . 52