FP-6.1 FP-6.2 6. Funktionen als Daten, Übersicht Notation von Lambda-Ausdrücken Orthogonales Typsystem: Funktionen sind beliebig mit anderen Typen kombinierbar Auswertung eines Lambda-Ausdruckes liefert eine Funktion, als Datum, unbenannt. Notation für Funktionswerte (Lambda-Ausdruck): fn (z,k) => z*k Notation: Datenstrukturen mit Funktionen als Komponenten: z. B. Suchbaum für Funktionen fn ParameterMuster => Ausdruck Funktionale, Funktionen höherer Ordnung (higher order functions, HOF): haben Funktionen als Parameter oder als Ergebnis fn (z,k) => z*k fn (x, y) => Math.sqrt (x*x + y*y) mit Fallunterscheidung: Berechnungsschemata: Funktion als Parameter abstrahiert Operation im Schema, wird bei Aufruf des Schemas konkretisiert (hier noch ohne Currying) schrittweise Parametrisierung (Currying): Funktion als Ergebnis bindet ersten Parameter, nützliche Programmiertechnik, steigert Wiederverwendbarkeit val chorner = fn l => fn x => foldl (fn (z,k) => z*x+k, l, 0); nicht-endliche Datenstrukturen (Ströme, lazy evaluation), (Kapitel 7): Funktionen als Komponenten von Datenstrukturen, z. B. Funktion, die den Rest einer Liste liefert datatype 'a seq = Nil | Cons of 'a * (unit -> 'a seq) Muster1 => Ausdruck1 Muster2 => Ausdruck2 ... Mustern => Ausdruckn fn nil => true | (_::_) => false © 2004 bei Prof. Dr. Uwe Kastens © 2012 bei Prof. Dr. Uwe Kastens foldl (fn (z,k) => z*k, [2,5,1], 1); fn | | | Anwendungen von Lambda-Ausdrücken: linsert (l, fn (z,k) => z*x+k, 0) (fn (z,k) => z*k) (a, b) if b then fn (z,k) => z*k else fn (z,k) => z+k [fn (z,k) => z*k, fn (z,k) => z+k] val null = fn nil => true | (_::_) => false; fun Comp (f, g) = fn x => f (g x); FP-6.3 FP-6.4 Currying Funktionen in Datenstrukturen Haskell B. Curry: US-amerikanischer Logiker 1900-1982, Combinatory Logic (1958); M. Schönfinkel hatte die Idee schon 1924: Statt Parametertupel schrittweise parametrisieren: fun prefix (pre, post) = pre ^ post; Signatur: string * string -> string curried: fun prefix pre = fn post => pre ^ post; Signatur: string -> (string -> string) gleich: string -> string -> string Erster Parameter (pre) ist in der Ergebnisfunktion gebunden. Kurznotation: fun prefix pre post = pre ^ post; Liste von Funktionen: val titlefns = [prefix "Sir ", prefix "The Duke of ", prefix "Lord "] hd (tl titlefns) "Gloucester"; Curry-Form von Funktionen ist allgemeiner verwendbar als Tupelform! Suchbaum mit (string * (real -> real)) Paaren: val fntree = Dict.insert (Dict.insert (Dict.insert (Lf, "sin", Math.sin), "cos", Math.cos), "atan", Math.atan); fun repnlist n x = if n=0 then [] else x :: repnlist (n-1) x; © 2004 bei Prof. Dr. Uwe Kastens © 2004 bei Prof. Dr. Uwe Kastens Anwendungen: val knightify = prefix "Sir "; val dukify = prefix "The Duke of "; knightify "Ratcliff"; (prefix "Sir ") "Ratcliff"; prefix "Sir " "Ratcliff"; linksassoziativ auch rekursiv: x oder n ist in der Ergebnisfunktion gebunden fun repxlist x n = if n=0 then [] else x :: repxlist x (n-1); :(string -> string) list Dict.lookup (fntree, "cos") 0.0; FP-6.5 FP-6.6 Currying als Funktional Komposition von Funktionen Funktional: Funktionen über Funktionen; Funktionen höherer Ordnung (HOF) Ausdrücke mit Operatoren, die Funktionen zu neuen Funktionen verknüpfen infix o; fun (f o g) x = f (g x); ('b->'c) * ('a->'b) -> 'a->'c secl, secr (section): 2-stellige Funktion in Curry-Form wandeln; dabei den linken, rechten Operanden binden: fun secl x f y = f (x, y); 'a -> ('a * 'b -> 'c) -> 'b -> 'c fn x => 2.0 / (x - 1.0)entspricht (secl 2.0 op/) o (secr op- 1.0) Potenzieren von Funktionen fn(x) : fun repeat f n x = if n > 0 then repeat f (n-1) (f x) else x; ('a->'a) -> int -> 'a -> 'a (repeat secr op/ 2.0 3) (800.0) fun secr f y x = f (x, y); ('a * 'b -> 'c) -> 'b -> 'a -> 'c val twoPow = secl 2.0 power; int -> real val pow3 = secr power 3; real -> real klassische Kombinatoren S K I: © 2004 bei Prof. Dr. Uwe Kastens © 2004 bei Prof. Dr. Uwe Kastens Anwendungen: fun power (x, k):real =if k = 1 then x else if k mod 2 = 0then power (x*x, k div 2) else x *power (x*x, k div 2); map (l, secr power 3); val knightify = (secl "Sir " op^); string -> string op^ bedeutet infix-Operator ^ als Funktion FP-6.7 Reihenberechnung als Schema Allgemeine Formel für eine endliche Reihe: Σ i=0 m-1 f(i) fun summation f m = let fun sum (i, z):real = akkumulierende Hilfsfunktion if i=m then z else sum (i+1, z + (f i)) in sum (0, 0.0) end; Signatur: (int->real) -> int -> real Aufruf summation (fn k => real(k*k)) 5; liefert 30 Doppelsumme: Σ i=0 Σ j=0 m-1 n-1 g(i,j) summation als Parameter von summation: © 2008 bei Prof. Dr. Uwe Kastens Bindung summation(fn i => summation (fn j => g(i,j)) n) m int->real int->real einfacher h i j statt g(i,j): summation (fn i => summation (h i) n) m; Kombination von Funktionen, Konversion nach real: summation (Math.sqrt o real); Summe konstanter Werte; Kombinator K für konstante Funktion: summation (K 7.0) 10; fun I x = x; 'a -> 'a fun K x y = x; 'a -> 'b -> 'a fun S x y z = x z (y z); ('a -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'c allgemeine Form der Komposition. I entspricht S K K