Weitere Aspekte von Funktionen in Haskell

Werbung
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 . . .
Herunterladen