Praktische Informatik 3: Funktionale Programmierung Vorlesung 6 vom 20.11.2018: Funktionen Höherer Ordnung I
Christoph Lüth
Universität Bremen Wintersemester 2018/19
16:03:08 2018-12-18 1 [35]
Fahrplan
I Teil I: Funktionale Programmierung im Kleinen
IEinführung
IFunktionen
IAlgebraische Datentypen
ITypvariablen und Polymorphie
IZyklische Datenstrukturen
I Funktionen höherer Ordnung I
IFunktionen höherer Ordnung II
I Teil II: Funktionale Programmierung im Großen
I Teil III: Funktionale Programmierung im richtigen Leben
PI3 WS 18/19 2 [35]
Inhalt
I Funktionenhöherer Ordnung:
I Funktionen alsgleichberechtigte Objekte
I Funktionen alsArgumente
I Spezielle Funktionen:map,f i l t e r,foldund Freunde
PI3 WS 18/19 3 [35]
Funktionen als Werte
PI3 WS 18/19 4 [35]
Funktionen Höherer Ordnung
Slogan
“Functions are first-class citizens.”
I Funktionen sindgleichberechtigt: Ausdrücke wiealle anderen
I Grundprinzipder funktionalen Programmierung
I Modellierungallgemeiner Berechungsmuster
I Kontrollabstraktion
PI3 WS 18/19 5 [35]
Ähnliche Datentypen der letzten Vorlesung
dataLager = LeeresLager
| Lager A r t i k e l Menge Lager dataEinkaufswagen = LeererWagen
| Einkauf A r t i k e l Menge Einkaufswagen data String = Empty
| Char : + String I einkonstanterKonstruktor
I einlinear rekursiverKonstruktor
Gelöst durch Polymorphie
PI3 WS 18/19 6 [35]
Ähnliche Funktionen der letzten Vorlesung
kasse :: Einkaufswagen→ Int kasse LeererWagen = 0
kasse ( Einkauf a m e) = cent a m+ kasse e inventur :: Lager→ Int
inventur LeeresLager = 0
inventur (Lager a m l ) = cent a m+ inventur l length :: String→ Int
length Empty = 0
length (c : + s ) = 1+ length s Gemeinsamkeiten:
I ein Fall pro Konstruktor I linearerrekursiver Aufruf
I Nichtdurch Polymorphie gelöst (keine InstanzeinerDefinition)
PI3 WS 18/19 7 [35]
Ein einheitlicher Rahmen
I Zwei ähnliche Funktionen:
toL :: String→String toL [ ] = [ ]
toL (c : cs ) = toLower c : toL cs
toU :: String→ String toU [ ] = [ ]
toU (c : cs ) = toUpper c : toU cs I Warum nichteineFunktion . . . undzweiInstanzen?
map f [ ] = [ ]
map f (c : cs ) = f c : map f cs toL cs = map toLower cs toU cs = map toUpper cs I FunktionfalsArgument
I Was hättemapfür einenTyp?
PI3 WS 18/19 8 [35]
Funktionen als Werte: Funktionstypen
I Was hättemapfür einenTyp?
map f [ ] = [ ]
map f (c : cs ) = f c : map f cs I Was ist der Typ desersten Arguments?
I Eine Funktion mit beliebigen Definitions- und Wertebereich:α→β I Was ist der Typ deszweiten Arguments?
I Eine Liste, auf deren Elemente die Funktionfangewant wird:[α]
I Was ist derErgebnistyp?
I Eine Liste von Elementen aus dem Wertebereich vonf:[β]
I Alleszusammengesetzt:
map :: (α→β)→ [α]→ [β]
PI3 WS 18/19 9 [35]
Map und Filter
PI3 WS 18/19 10 [35]
Funktionen als Argumente: map
Imapwendet Funktion auf alle Elemente an I Signatur:
map :: (α→β)→ [α]→ [β]
map f [ ] = [ ]
map f (c : cs ) = f c : map f cs I Auswertung:
toL "AB" →map toLower ( ’A’ : ’B’ : [ ] )
→toLower ’A’ : map toLower ( ’B’ : [ ] )
→’a ’ :map toLower ( ’B’ : [ ] )
→’a ’ : toLower ’B’ :map toLower [ ]
→’a ’ : ’ b ’ :map toLower [ ]
→’a ’ : ’ b ’ : [ ]≡"ab"
I Funktionsausdrückewerden symbolisch reduziert
I Keine Änderung
PI3 WS 18/19 11 [35]
Funktionen als Argumente: f i l t e r
I Elementefiltern:f i l t e r I Signatur:
f i l t e r :: (α→ Bool)→ [α]→ [α]
I Definition
f i l t e r p [ ] = [ ] f i l t e r p (x : xs )
| p x = x : f i l t e r p xs
| otherwise = f i l t e r p xs I Beispiel:
l e t t e r s :: String→ String l e t t e r s = f i l t e r isAlpha
PI3 WS 18/19 12 [35]
Beispiel f i l t e r : Sieb des Erathostenes
I Für jedegefundene PrimzahlpalleVielfachenheraussieben:
sieve (p : ps ) = p : sieve ( f i l t e r ps ) where f i l t e r (q : qs )
| q ‘mod‘ p6= 0 = q : f i l t e r qs
| otherwise = f i l t e r qs I Einfacher mitf i l t e r
I Es wird gefiltert mitmod q p6= 0(Funktionsparameterq) I Namenlose(anonyme) Funktionλq→mod q p6= 0
sieve :: [ Integer ]→ [ Integer ]
sieve (p : ps ) = p : sieve ( f i l t e r (λq→q ‘mod‘ p6= 0) ps )
PI3 WS 18/19 13 [35]
Funktionen Höherer Ordnung
PI3 WS 18/19 14 [35]
Funktionen als Argumente: Funktionskomposition
I Funktionskomposition(mathematisch) (◦) :: (β→γ) → (α→β)→α→γ
( f◦g) x = f (g x)
I Vordefiniert
I Lies:fnachg
I Funktionskompositionvorwärts:
(>.>) :: (α→β)→ (β→γ)→α→ γ ( f>.>g) x = g ( f x)
I Nichtvordefiniert
PI3 WS 18/19 15 [35]
η-Kontraktion
I “>.>ist dasselbe wie ◦ nur mit vertauschten Argumenten”
I Vertauschen derArgumente(vordefiniert):
f l i p :: (α→β→γ)→β→α→γ f l i p f b a = f a b
I Damit Funktionskomposition vorwärts:
(>.>) :: (α→β)→ (β→γ)→α→γ (>.>) = f l i p (◦)
I Da fehlt doch was?! Nein:
(>.>) = flip (◦) ≡ (>.>) f g a = flip (◦) f g a I Warum?
PI3 WS 18/19 16 [35]
η-Äquivalenz und η-Kontraktion
η-Äquivalenz
Seif eine Funktionf:A→B, dann giltf=λx.f x
I In Haskell:η-Kontraktion
I Bedingung: AusdruckE :: α→β, Variablex :: α,Edarfxnicht enthalten λx→E x ≡ E
I SpezialfallFunktionsdefinition(punktfreieNotation) f x = E x ≡ f = E I Hier:
(>.>) f g a = flip (◦) f g a ≡ (>.>) f g a = flip (◦) f g a
PI3 WS 18/19 17 [35]
Partielle Applikation
I Funktionskonstruktorrechtsassoziativ:
α→β→γ≡α→ (β→γ)
IInbesondere:(α→β)→γ6=α→(β→γ) I Funktionsanwendung istlinksassoziativ:
f a b≡( f a) b
IInbesondere:f (a b)6=( f a) b I PartielleAnwendung von Funktionen:
IFürf :: α→β→γ,x :: αistf x :: β→γ I Beispiele:
Imap toLower :: String→String
I (3 ==) :: Int→Bool
I concat◦map ( r e p l i c a t e 2) :: String→String
PI3 WS 18/19 18 [35]
Strukturelle Rekursion
PI3 WS 18/19 19 [35]
Strukturelle Rekursion
I Strukturelle Rekursion: gegeben durch
Ieine Gleichungfür dieleere Liste
Ieine Gleichungfür dienicht-leere Liste (miteinemrekursiven Aufruf)
I Beispiel:kasse,inventur,sum,concat, length,(++), . . .
I Auswertung:
sum [4 ,7 ,3] → 4 + 7 + 3 + 0 concat [A, B, C] → A ++ B ++ C++ [ ] length [4 , 5 , 6] → 1+ 1+ 1+ 0
x1 x2 x3 x4
E
PI3 WS 18/19 20 [35]
Strukturelle Rekursion
I Allgemeines Muster:
f [ ] = e
f (x : xs ) = x⊗f xs I Parameterder Definition:
I Startwert (für die leere Liste)e :: β
I Rekursionsfunktion⊗ :: α→β→β I Auswertung:
f [ x1 , . . ., xn ] = x1⊗x2⊗. . .⊗xn⊗e I Terminiertimmer (wenn Listeendlichund⊗,eterminieren)
PI3 WS 18/19 21 [35]
Strukturelle Rekursion durch f o l d r
I StukturelleRekursion
IBasisfall: leere Liste
IRekursionsfall: Kombination aus Listenkopf und Rekursionswert
I Signatur
f o l d r :: (α→β→β)→β→ [α]→β
I Definition
f o l d r f e [ ] = e
f o l d r f e (x : xs ) = f x ( f o l d r f e xs )
PI3 WS 18/19 22 [35]
Beispiele: f o l d r
I Summierenvon Listenelementen.
sum :: [ Int ]→ Int sum xs = f o l d r (+) 0 xs I Flachklopfenvon Listen.
concat :: [ [ a ] ]→ [ a ] concat xs = f o l d r (++) [ ] xs
I Längeeiner Liste length :: [ a ]→ Int
length xs = f o l d r (λx n→n+ 1) 0 xs
PI3 WS 18/19 23 [35]
Beispiele: f o l d r
I Konjunktioneiner Liste and :: [ Bool ] → Bool and xs = f o l d r (&&) True xs
I Konjunktionvon Prädikaten a l l :: (α→ Bool)→ [α] → Bool a l l p = and◦map p
PI3 WS 18/19 24 [35]
Der Shoppe, revisited.
I Kassealt:
kasse :: Einkaufswagen→ Int kasse (Ekwg ps ) = kasse ’ pswhere
kasse ’ [ ] = 0
kasse ’ (p : ps ) = cent p+ kasse ’ ps I Kasseneu:
kasse ’ :: Einkaufswagen→ Int
kasse ’ (Ekwg ps ) = f o l d r (λp ps→ cent p+ ps ) 0 ps Besser:
kasse :: Einkaufswagen→ Int kasse (Ekwg ps ) = sum (map cent ps)
PI3 WS 18/19 25 [35]
Der Shoppe, revisited.
I Inventuralt:
inventur :: Lager→ Int
inventur (Lager ps ) = inventur ’ ps where inventur ’ [ ] = 0
inventur ’ (p : ps ) = cent p+ inventur ’ ps
I Suche nach einem Artikelneu:
inventur :: Lager→ Int
inventur (Lager l ) = sum (map cent l )
PI3 WS 18/19 26 [35]
Der Shoppe, revisited.
I Suche nach einem Artikelalt:
suche :: A r t i k e l→ Lager→Maybe Menge suche art (Lager ps ) = suche ’ art pswhere
suche ’ art (Posten l a r t m: l )
| art == l a r t = Just m
| otherwise = suche ’ art l suche ’ art [ ] = Nothing I Suche nach einem Artikelneu:
suche :: A r t i k e l→ Lager→Maybe Menge suche a (Lager ps ) =
listToMaybe (map (λ(Posten _ m)→m)
( f i l t e r (λ(Posten l a _) → l a == a) ps ))
PI3 WS 18/19 27 [35]
Der Shoppe, revisited.
I Kassenbon formatierenneu:
kassenbon :: Einkaufswagen→ String kassenbon ew@(Ekwg ps ) =
"Bob’ s␣Aulde␣Grocery␣Shoppe\n\n"++
" A r t i k e l ␣␣␣␣␣␣␣␣␣␣␣␣␣␣Menge␣␣␣␣␣␣Preis\n"++
"−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\n"++ concatMap a r t i k e l ps ++
"=====================================\n"++
"Summe: "++ formatR 31 (showEuro ( kasse ew)) a r t i k e l :: Posten→ String
PI3 WS 18/19 28 [35]
Noch ein Beispiel: rev
I Listenumdrehen:
rev1 :: [α]→ [α]
rev1 [ ] = [ ]
rev1 (x : xs ) = rev1 xs ++ [ x ]
I Mitf o l d r:
rev2 :: [α]→ [α]
rev2 = f o l d r (λx xs→ xs++ [ x ] ) [ ]
I Unbefriedigend: doppelte RekursionO(n2)!
PI3 WS 18/19 29 [35]
Iteration mit f o l d l
I f o l d rfaltet vonrechts:
f o l d r⊗[ x1 , . . ., xn ] e = x1⊗x2 (x2⊗( . . . (xn⊗e ))) I Warum nichtandersherum?
f o l d l⊗[ x1 , . . ., xn ] e = ((( e⊗x1)⊗x2).. .)⊗xn I Definition vonf o l d l:
f o l d l :: (α→β →α) →α→ [β] →α f o l d l f a [ ] = a
f o l d l f a (x : xs ) = f o l d l f ( f a x) xs
I f o l d list einIteratormit Anfangszustande, Iterationsfunktion⊗ I Entspricht einfacher Iteration (for-Schleife)
PI3 WS 18/19 30 [35]
f o l d r vs. f o l d l
I f = f o l d r⊗eentspricht
f [ ] = e
f (x : xs ) = x⊗f xs
I Nicht-striktinxs, z.B.and,or
I Konsumiert nicht immer die ganze Liste
I Auch für unendliche Listen anwendbar
I f = f o l d l⊗eentspricht f xs = g e xswhere
g a [ ] = a
g a (x : xs ) = g (a⊗x) xs
I Effizient(endrekursiv) undstriktinxs
I Konsumiert immer die ganze Liste
I Divergiert immer für unendliche Listen
PI3 WS 18/19 31 [35]
Beispiel: rev revisited
I Listenumkehrendrekursiv:
rev3 :: [α]→ [α]
rev3 xs = rev0 xs [ ] where rev0 [ ] ys = ys
rev0 (x : xs ) ys = rev0 xs (x : ys ) I Listenumkehr durch faltenvon links:
rev4 :: [α]→ [α]
rev4 = f o l d l (λxs x → x : xs ) [ ] rev5 :: [α]→ [α]
rev5 = f o l d l ( f l i p ( : ) ) [ ] I Nur nocheineRekursionO(n)!
PI3 WS 18/19 32 [35]
Wann ist f o l d l = f o l d r ?
Definition (Monoid) (⊗,A) ist einMonoidwenn
A⊗x = x (Neutrales Element links) x⊗A= x (Neutrales Element rechts) (x⊗y)⊗z = x⊗(y⊗z) (Assoziativät)
Theorem
Wenn(⊗,A)Monoid, dann für alleA,xs
foldl⊗A xs=foldr⊗A xs
I Beispiele:length,concat,sum I Gegenbeispiele:rev,a l l
PI3 WS 18/19 33 [35]
Übersicht: vordefinierte Funktionen auf Listen II
map :: (α→β)→ [α]→ [β] −−Auf alle anwenden f i l t e r :: (α→ Bool)→ [α]→ [α] −−Elemente filtern f o l d r :: (α→β→β)→β→ [α]→β −−Falten von rechts f o l d l :: (β→α→β)→β→ [α]→β −−Falten von links mapConcat :: (α→ [β] )→ [α]→ [β] −−map und concat takeWhile :: (α→ Bool)→ [α]→ [α] −−längster Prefix mit p dropWhile :: (α→ Bool)→ [α]→ [α] −−Rest von takeWhile span :: (α→ Bool)→ [α]→ ( [α] , [α] )−−takeWhile und dropWhile a l l :: (α→ Bool)→ [α] →Bool −−p gilt für alle
any :: (α→ Bool)→ [α] →Bool −−p gilt mind. einmal elem :: (Eqα) ⇒α→ [α] →Bool −−Ist Element enthalten?
zipWith :: (α→β →γ) → [α] → [β] → [γ]
−−verallgemeinertes zip
I Mehr: sieheData . L i s t
PI3 WS 18/19 34 [35]
Zusammenfassung
I Funktionenhöherer Ordnung
I Funktionen alsgleichberechtigte ObjekteundArgumente
I Partielle Applikation,η-Kontraktion, namenlose Funktionen
I Spezielle Funktionen höherer Ordnung:map,f i l t e r,foldund Freunde I Formen derRekursion:
I StrukturelleRekursion entsprichtf o l d r
I Iteration entsprichtf o l d l
I Nächste Woche:foldfür andere Datentypen
PI3 WS 18/19 35 [35]