Praktische Informatik 3: Funktionale Programmierung Vorlesung 5 vom 30.11.2020: Funktionen Höherer Ordnung I
Christoph Lüth
Wintersemester 2020/21
11:51:18 2021-02-22 1 [39]
Fahrplan
ITeil I: Funktionale Programmierung im Kleinen IEinführung
IFunktionen
IAlgebraische Datentypen ITypvariablen und Polymorphie IFunktionen höherer Ordnung I IRekursive und zyklische Datenstrukturen IFunktionen höherer Ordnung II
ITeil II: Funktionale Programmierung im Großen ITeil III: Funktionale Programmierung im richtigen Leben
PI3 WS 20/21 2 [39]
Inhalt
IFunktionenhöherer Ordnung: IFunktionen alsgleichberechtigte Objekte IFunktionen alsArgumente
ISpezielle Funktionen:map,filter,foldund Freunde Lernziel
Wir verstehen, wie wir mitmap,filterundfoldwiederkehrende Funktionsmuster kürzer und verständlicher aufschreiben können, und wir verstehen, warum der Funktionstyp in α→βein Typ wie jeder andere ist.
PI3 WS 20/21 3 [39]
I. Funktionen als Werte
PI3 WS 20/21 4 [39]
Funktionen Höherer Ordnung
Slogan
“Functions are first-class citizens.”
IFunktionen sindgleichberechtigt: Ausdrücke wiealle anderen IGrundprinzipder funktionalen Programmierung
IModellierungallgemeiner Berechungsmuster IKontrollabstraktion
PI3 WS 20/21 5 [39]
Ähnliche Datentypen der letzten Vorlesung
data Lager=LeeresLager
| Lager Artikel Menge Lager data Einkaufskorb=LeererKorb
| Einkauf Artikel Menge Einkaufskorb data MyString=Empty
| Char :+ MyString IeinkonstanterKonstruktor
Ieinlinear rekursiverKonstruktor Gelöst durch Polymorphie
PI3 WS 20/21 6 [39]
Ähnliche Funktionen der letzten Vorlesung
kasse :: Einkaufskorb→Int kasse LeererKorb=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 :: MyString→Int
length Empty =0
length (c :+ s)=1+ length s Gemeinsamkeiten:
Iein Fall pro Konstruktor Ilinearerrekursiver Aufruf
Nichtdurch Polymorphie gelöst
PI3 WS 20/21 7 [39]
Ein einheitlicher Rahmen
IZwei ähnliche Funktionen:
toL :: String→String toL [ ] =[ ]
toL (c:cs)=toLower c : toL cs
toU :: String→String toU [ ] =[ ]
toU (c:cs)=toUpper c : toU cs IWarum nichteineFunktion . . . undzweiInstanzen?
map f [ ] =[ ]
map f (c:cs)=f c : map f cs toL cs=map toLower cs toU cs=map toUpper cs IFunktionfalsArgument
IWas hättemapfür einenTyp?
PI3 WS 20/21 8 [39]
Funktionen als Werte: Funktionstypen
IWas hättemapfür einenTyp?
map f [ ] =[ ]
map f (c:cs)=f c : map f cs IWas ist der Typ desersten Arguments?
IEine Funktion mit beliebigen Definitions- und Wertebereich:α→β IWas ist der Typ deszweiten Arguments?
IEine Liste, auf deren Elemente die Funktionfangewant wird:[α]
IWas ist derErgebnistyp?
IEine Liste von Elementen aus dem Wertebereich vonf:[β]
IAlleszusammengesetzt:
map :: (α→β)→[α]→[β]
PI3 WS 20/21 9 [39]
Was zum Selberdenken.
DiekonstanteFunktion ist const :: α→β→α const c _=c
Übung 5.1: Was macht diese Funktion?
mystery xs=sum (map (const 1) xs) Lösung:Betrachten wir eine Beispiel-Auswertung:
sum (map (const 1) [ ]) sum [ ] 0
sum (map (const 1) [True, False, True]) sum [1,1,1] 3 sum (map (const 1) "foobaz") sum ([1,1,1,1,1,1]) 6 Die mysteriöse Funktion berechnet dieLängeder Listexs!
PI3 WS 20/21 10 [39]
II. Map und Filter
PI3 WS 20/21 11 [39]
Funktionen als Argumente: map
Imapwendet Funktion auf alle Elemente an ISignatur:
map :: (α→β)→[α]→[β]
map f [ ] =[ ]
map f (c:cs)=f c : map f cs
x
1x
2x
3x
4f
y1 y2 y3 y4
f f f
IAuswertung:
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"
IFunktionsausdrückewerden symbolisch reduziert IKeine Änderung
PI3 WS 20/21 12 [39]
Funktionen als Argumente: filter
IElementefiltern:filter ISignatur:
filter :: (α→Bool)→[α]→[α]
IDefinition
filter p [ ] =[ ] filter p (x:xs)
| p x =x: filter p xs
| otherwise=filter p xs
x
1x
2x
3x
4x
1x
2x
4p p p
IBeispiel:
digits :: String→String digits=filter isDigit
PI3 WS 20/21 13 [39]
Beispiel filter: Sieb des Erathostenes
IFür jedegefundene PrimzahlpalleVielfachenheraussieben:
sieve’ :: [Integer]→[Integer]
sieve’ (p:ps)=p: sieve’ (filterPs ps)where filterPs (q: qs)
| q ‘mod‘ p6=0=q: filterPs qs
| otherwise =filterPs qs
I„Sieb“: es werden alleqgefiltert mitmod q p6=0
PI3 WS 20/21 14 [39]
Beispiel filter: Sieb des Erathostenes
IEs werden alleqgefiltert mitmod q p6=0 INamenlose(anonyme) Funktionλq→mod q p6=0
sieve :: [Integer]→[Integer]
sieve (p:ps)=p: sieve (filter (λq→q ‘mod‘ p6=0) ps) IDamit (NB: kleinste Primzahl ist2):
primes :: [Integer]
primes=sieve [2..]
IPrimzahlzählfunktionπ(n):
pcf :: Integer→Int
pcf n=length (takeWhile (λm→ m<n) primes)
Primzahltheorem:
n→∞lim π(n)
n/logn= 1 DEMO
PI3 WS 20/21 15 [39]
Jetzt seit ihr dran. . .
Für das Palindrom hatten wir eine Funktioncleandefiniert:
clean :: String→String clean [ ]=[ ]
clean (s:xs) | isAlphaNum s=toLower s : clean xs
| otherwise =clean xs Übung 5.2:Cleanrefactored
Wie siehtcleanmitmapundfilter(undohne Rekursion) aus?
Lösung:
clean’ :: String→String
clean’ xs=map toLower (filter isAlphaNum xs)
PI3 WS 20/21 16 [39]
III. Strukturelle Rekursion
PI3 WS 20/21 17 [39]
Strukturelle Rekursion
IStrukturelle Rekursion: gegeben durch Ieine Gleichungfür dieleere Liste Ieine Gleichungfür dienicht-leere Liste
(miteinemrekursiven Aufruf)
IBeispiel:kasse,inventur,sum,concat,length,(++), . . .
IAuswertung:
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 20/21 18 [39]
Strukturelle Rekursion
IAllgemeines Muster: f [ ] =e f (x:xs)=x⊗f xs IParameterder Definition:
IStartwert (für die leere Liste)e :: β IRekursionsfunktion⊗:: α→β→β IAuswertung:
f [x1,..., xn]=x1⊗x2⊗...⊗xn⊗e ITerminiertimmer (wenn Listeendlichund⊗,eterminieren)
PI3 WS 20/21 19 [39]
Strukturelle Rekursion durch foldr
IStukturelleRekursion IBasisfall: leere Liste
IRekursionsfall: Kombination aus Listenkopf und Rekursionswert ISignatur
foldr :: (α→β→β)→β→[α]→β IDefinition
foldr f e [ ] =e
foldr f e (x:xs)=f x (foldr f e xs)
PI3 WS 20/21 20 [39]
Beispiele: foldr
ISummierenvon Listenelementen.
sum :: [Int]→Int sum xs=foldr (+) 0 xs IFlachklopfenvon Listen.
concat :: [[a]]→[a]
concat xs=foldr (++) [ ] xs ILängeeiner Liste
length :: [a]→Int
length xs=foldr (λx n→n+ 1) 0 xs
PI3 WS 20/21 21 [39]
Beispiele: foldr
IKonjunktioneiner Liste and :: [Bool]→Bool and xs=foldr (&&) True xs
IKonjunktionvon Prädikaten all :: (α→Bool)→[α] →Bool all p xs=and (map p xs)
PI3 WS 20/21 22 [39]
Der Shoppe, revisited.
IKassealt:
kasse :: Einkaufskorb→Int kasse (Ekwg ps)=kasse’ pswhere
kasse’ [ ]=0
kasse’ (p: ps)=cent p+ kasse’ ps IKasseneu:
kasse’ :: Einkaufskorb→Int
kasse’ (Ek ps)=foldr (λp ps→cent p+ ps) 0 ps Besser:
kasse :: Einkaufskorb→Int kasse (Ek ps)=sum (map cent ps)
PI3 WS 20/21 23 [39]
Der Shoppe, revisited.
IInventuralt:
inventur :: Lager→Int
inventur (Lager ps)=inventur’ ps where inventur’ [ ]=0
inventur’ (p: ps)=cent p+ inventur’ ps
ISuche nach einem Artikelneu:
inventur :: Lager→Int
inventur (Lager l)=sum (map cent l)
PI3 WS 20/21 24 [39]
Der Shoppe, revisited.
ISuche nach einem Artikelalt:
suche :: Artikel→Lager→Maybe Menge suche art (Lager ps)=suche’ art pswhere
suche’ art (Posten lart m: l)
| art==lart=Just m
| otherwise =suche’ art l suche’ art [ ] =Nothing ISuche nach einem Artikelneu:
suche :: Artikel→Lager→Maybe Menge suche a (Lager ps)=
listToMaybe (map (λ(Posten _ m)→m)
(filter (λ(Posten la _) →la==a) ps))
PI3 WS 20/21 25 [39]
Der Shoppe, revisited.
IKassenbon formatierenneu:
kassenbon :: Einkaufskorb→String kassenbon ek@(Ek ps)=
"Bob’s␣Aulde␣Grocery␣Shoppe\n\n"++
"Artikel␣␣␣␣␣␣␣␣␣␣␣␣␣␣Menge␣␣␣␣␣␣Preis\n"++
"---\n"++
concatMap artikel ps++
"=====================================\n"++
"Summe:"++formatR 31 (showEuro (kasse ek)) artikel :: Posten→String
PI3 WS 20/21 26 [39]
Noch ein Beispiel: rev
IListenumdrehen:
rev1 :: [α]→[α]
rev1 [ ] =[ ]
rev1 (x:xs)=rev1 xs++[x]
IMitfoldr:
rev2 :: [α]→[α]
rev2=foldr (λx xs→xs++[x]) [ ] IUnbefriedigend: doppelte RekursionO(n2)!
PI3 WS 20/21 27 [39]
Iteration mit foldl
Ifoldrfaltet vonrechts:
foldr⊗[x1,..., xn] e=x1⊗x2 (x2⊗(...(xn⊗e))) IWarum nichtandersherum?
foldl⊗[x1,..., xn] e=(((e⊗x1)⊗x2)...)⊗xn IDefinition vonfoldl:
foldl :: (α→β →α) →α→[β] →α foldl f a [ ]=a
foldl f a (x:xs)=foldl f (f a x) xs
Ifoldlist einIteratormit Anfangszustande, Iterationsfunktion⊗ IEntspricht einfacher Iteration (for-Schleife)
PI3 WS 20/21 28 [39]
Beispiel: rev revisited
IListenumkehrendrekursiv:
rev3 :: [α]→[α]
rev3 xs=rev0 xs [ ]where rev0 [ ] ys=ys
rev0 (x:xs) ys=rev0 xs (x:ys) IListenumkehr durch faltenvon links:
rev4 :: [α]→[α]
rev4=foldl (λxs x →x: xs) [ ] rev5 :: [α]→[α]
rev5=foldl (flip (:)) [ ] INur nocheineRekursionO(n)!
PI3 WS 20/21 29 [39]
foldr vs. foldl
If=foldr⊗eentspricht f [ ] =e f (x:xs)=x⊗f xs INicht-striktinxs, z.B.and,or IKonsumiert nicht immer die ganze Liste IAuch für unendliche Listen anwendbar If=foldl⊗eentspricht
f xs=g e xswhere g a [ ] =a
g a (x:xs)=g (a⊗x) xs IEffizient(endrekursiv) undstriktinxs IKonsumiert immer die ganze Liste IDivergiert immer für unendliche Listen
x1 x2 x3 x4
e
x1 x2 x3 x4
e
PI3 WS 20/21 30 [39]
Wann ist foldl = foldr?
Definition (Monoid) (⊗,e) ist einMonoidwenn
e⊗x=x (Neutrales Element links)
x⊗e=x (Neutrales Element rechts)
(x⊗y)⊗z=x⊗(y⊗z) (Assoziativät)
Theorem
Wenn(⊗,e)Monoidund⊗strikt, dann gilt für allee,xs foldl⊗e xs=foldr⊗e xs IBeispiele:concat,sum,product,length,reverse IGegenbeispiel:all,any(nicht-strikt)
PI3 WS 20/21 31 [39]
Übersicht: vordefinierte Funktionen auf Listen II
map :: (α→β)→[α]→[β] −− Auf alle Elemente anwenden filter :: (α→Bool)→[α]→[α] −− Elemente filtern foldr :: (α→β→β)→β→[α]→β −− Falten von rechts foldl :: (β→α→β)→β→[α]→β −− Falten von links mapConcat :: (α→[β])→[α]→[β] −− map und concat takeWhile :: (α→Bool)→[α]→ [α] −− längster Prefix mit p dropWhile :: (α→Bool)→[α]→ [α] −− Rest von takeWhile span :: (α→Bool)→[α]→([α], [α]) −− takeWhile und dropWhile all :: (α→Bool)→[α]→Bool −− Argument gilt für alle any :: (α→Bool)→[α]→Bool −− Argument gilt mind. einmal elem :: (Eqα)⇒α→[α]→Bool −− Ist Element enthalten?
zipWith :: (α→β→γ)→[α] →[β] →[γ]−− verallgemeinertes zip IMehr: sieheData.List
PI3 WS 20/21 32 [39]
Jetzt seit ihr dran!
Übung 5.3:elemselbstgemacht Wie könnte die vordefinierte Funktion elem :: (Eqα) ⇒α→[α] →Bool definiert sein?
Lösung:Eine Möglichkeit:
elem x xs=not (null (filter (λy→ x==y) xs)) oder auch
elem x=not◦null◦filter (x==)
PI3 WS 20/21 33 [39]
IV. Funktionen Höherer Ordnung
PI3 WS 20/21 34 [39]
Funktionen als Argumente: Funktionskomposition
IFunktionskomposition(mathematisch) (◦):: (β→γ)→(α→β)→α→γ
(f◦g) x=f (g x) IVordefiniert ILies:fnachg
IFunktionskompositionvorwärts: (>.>) :: (α→β)→(β→γ)→α→γ (f>.>g) x=g (f x)
INichtvordefiniert
PI3 WS 20/21 35 [39]
η-Kontraktion
I“>.>ist dasselbe wie ◦nur mit vertauschten Argumenten”
IVertauschen derArgumente(vordefiniert):
flip :: (α→β→γ)→β→α→γ flip f b a=f a b
IDamit Funktionskomposition vorwärts:
(>.>) :: (α→β)→(β→γ)→α→γ (>.>)=flip (◦)
IDa fehlt doch was?! Nein:
(>.>) f g a = flip (◦) f g a ≡ (>.>) = flip (◦) IWarum?
PI3 WS 20/21 36 [39]
η-Äquivalenz und η-Kontraktion
η-Äquivalenz
Seifeine Funktionf:A→B, dann giltf=λx.f x IIn Haskell:η-Kontraktion
IBedingung: AusdruckE :: α→β, Variablex :: α,Edarfxnicht enthalten
λx→E x ≡ E ISpezialfallFunktionsdefinition(punktfreieNotation)
f x=E x ≡ f=E IHier:
(>.>) f g a = flip (◦) f g a ≡(>.>) f g a = flip (◦) f g a
PI3 WS 20/21 37 [39]
Partielle Applikation
IFunktionskonstruktorrechtsassoziativ:
α→β→γ≡α→(β→γ) IInbesondere:(α→β)→γ6=α→(β→γ)
IFunktionsanwendung istlinksassoziativ:
f a b≡(f a) b IInbesondere:f (a b)6=(f a) b
IPartielleAnwendung von Funktionen:
IFürf:: α→β→γ,x:: αistf x:: β→γ IBeispiele:
Imap toLower:: String→String I(3==):: Int→Bool
Iconcat◦map (replicate 2):: String→String
PI3 WS 20/21 38 [39]
Zusammenfassung
IFunktionenhöherer Ordnung
IFunktionen alsgleichberechtigte ObjekteundArgumente
ISpezielle Funktionen höherer Ordnung:map,filter,foldund Freunde IFormen derRekursion:
IStrukturelleRekursion entsprichtfoldr IIteration entsprichtfoldl
IPartielle Applikation,η-Äquivalenz, namenlose Funktionen INächste Woche: Rekursive und zyklische Datenstrukturen
PI3 WS 20/21 39 [39]