• Keine Ergebnisse gefunden

Praktische Informatik 3: Funktionale Programmierung Vorlesung 6 vom 22.11.2016: Funktionen Höherer Ordnung II und

N/A
N/A
Protected

Academic year: 2022

Aktie "Praktische Informatik 3: Funktionale Programmierung Vorlesung 6 vom 22.11.2016: Funktionen Höherer Ordnung II und"

Copied!
5
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Praktische Informatik 3: Funktionale Programmierung Vorlesung 6 vom 22.11.2016: Funktionen Höherer Ordnung II und

Effizienzaspekte

Christoph Lüth Universität Bremen Wintersemester 2016/17

16:02:27 2017-01-17 1 [34]

Fahrplan

I Teil I: Funktionale Programmierung im Kleinen

IEinführung

IFunktionen und Datentypen

IAlgebraische Datentypen

ITypvariablen und Polymorphie

IFunktionen höherer Ordnung I

I Funktionen höherer Ordnung II und Effizenzaspekte I Teil II: Funktionale Programmierung im Großen I Teil III: Funktionale Programmierung im richtigen Leben

PI3 WS 16/17 2 [34]

Heute

I Mehr übermapundfold

Imapundfoldsind nicht nur für Listen

I Effizient funktional programmieren

PI3 WS 16/17 3 [34]

map als strukturerhaltende Abbildung

I Der Datentyp()istterminal: es gibt für jeden Datentypαgenau eine total Abbildungα→ ()

I Struktur(Shape) eines DatentypsTαistT ()

IGegeben durch kanonische Funktionshape :: Tα→T (), dieαdurch ()ersetzt

IFür Listen:[ ( ) ]∼=Nat

mapist die kanonischestrukturerhaltende Abbildung I Fürmapgelten folgende Aussagen:

map id=id map f◦map g=map ( f◦g) shape◦map f=shape

PI3 WS 16/17 4 [34]

map und f i l t e r als Berechnungsmuster

Imap, f i l t e r,foldals Berechnungsmuster:

1.Anwenden einer Funktion aufjedesElement der Liste 2.möglicherweiseFilternbestimmter Elemente 3.Kombinationder Ergebnisse zu EndergebnisE I Gut parallelisierbar, skaliert daher als

Berechnungsmuster für große Datenmengen (big data)

x1 x2 x3 x4

E I Besondere Notation: Listenkomprehension

[ f x | x← as , g x ]≡ map f ( f i l t e r g as )

I Beispiel:

d i g i t s s t r = [ ord x−ord ’0 ’| x← str , i s D i g i t x ]

I Auch mit mehreren Generatoren:

idx = [ a : show i| a← [ ’ a ’ . . ’ z ’ ] , i← [ 0 . . 9 ] ]

PI3 WS 16/17 5 [34]

f o l d r ist kanonisch

f o l d rist diekanonische strukturell rekursiveFunktion.

I Alle strukturell rekursiven Funktionen sind als Instanz vonf o l d r darstellbar

I Insbesondere auchmapundf i l t e r(siehe Übungsblatt) I Es gilt:f o l d r ( : ) [ ]=id

I Jeder algebraischer Datentyp hat einf o l d r

PI3 WS 16/17 6 [34]

f o l d für andere Datentypen

foldist universell

Jeder algebraische DatentypThat genau einf o l d r.

I Kanonische Signatur fürT:

I Pro KonstruktorCein FunktionsargumentfC I Freie TypvariableβfürT

I Kanonische Definition:

I Pro KonstruktorCeine Gleichung

I Gleichung wendet FunktionsparameterfCauf Argumente an I Anmerkung: TypklasseFoldableschränkt Signatur vonf o l d rein data IL = Cons Int IL | Err String | Mt

f ol dIL :: ( Int→β→β)→ ( String→β)→β→ IL→β f ol dIL f e a (Cons i i l ) = f i ( f old IL f e a i l ) f ol dIL f e a ( Err s t r ) = e s t r

f ol dIL f e a Mt = a

f o l d für bekannte Datentypen

I Bool: Fallunterscheidung:

dataBool = False | True foldBool :: β→β→Bool→β foldBool a1 a2 False = a1 foldBool a1 a2 True = a2 IMaybeα: Auswertung

dataMaybeα= Nothing | Justα foldMaybe :: β→ (α→β)→Maybeα→β foldMaybe b f Nothing = b

foldMaybe b f ( Just a) = f a

IAlsmaybevordefiniert

(2)

f o l d für bekannte Datentypen

I Tupel: dieuncurry-Funktion

foldPair :: (α→β→γ)→ (α, β)→γ foldPair f (a , b)= f a b

I Natürliche Zahlen: Iterator dataNat = Zero | Succ Nat foldNat :: β→ (β→β)→Nat→β foldNat e f Zero = e

foldNat e f (Succ n) = f ( foldNat e f n)

PI3 WS 16/17 9 [34]

f o l d für binäre Bäume

I Binäre Bäume:

dataTreeα= Mt | Nodeα (Treeα) (Treeα)

ILabelnurin den Knoten

I Instanz vonfold:

foldT :: (α→β→β→β)→β→ Treeα→β foldT f e Mt = e

foldT f e (Node a l r ) = f a ( foldT f e l ) ( foldT f e r )

IInstanz vonmap, kein (offensichtliches) Filter

PI3 WS 16/17 10 [34]

Funktionen mit foldT und mapT

I Höhe des Baumes berechnen:

height :: Treeα→ Int

height = foldT (λ_ l r→1+ max l r ) 0

I Inorder-Traversion der Knoten:

inorder :: Treeα→ [α]

inorder = foldT (λa l r→ l ++ [ a ] ++ r ) [ ]

PI3 WS 16/17 11 [34]

Kanonische Eigenschaften von foldT und mapT

I Auch hier gilt:

foldT Node Mt=id mapT id=id mapT f◦mapT g=mapT ( f◦g) shape (mapT f xs )=shape xs

I Mitshape :: Treeα→Tree ()

PI3 WS 16/17 12 [34]

Das Labyrinth

I Das Labyrinth als variadischer Baum:

dataVTreeα= Nodeα [ VTreeα]

typeLabα= VTreeα

I Auch hierfürfoldTundmapT:

foldT :: (α→ [β]→β)→VTreeα→β foldT f (Node a ns ) = f a (map ( foldT f ) ns ) mapT :: (α→β)→ VTreeα→VTreeβ

mapT f (Node a ns ) = Node ( f a) (map (mapT f ) ns )

PI3 WS 16/17 13 [34]

Suche im Labyrinth

I Tiefensuche viafoldT dfts ’ :: Labα→ [ Pathα]

dfts ’ = foldT add where add a [ ] = [ [ a ] ]

add a ps = concatMap (map (a : ) ) ps I Problem:

I foldTterminiertnichtfürzyklischeStrukturen

IAuch nicht, wennaddprüft obaschon enthalten ist

IPfade werden vomEndekonstruiert

PI3 WS 16/17 14 [34]

Effizienzaspekte

PI3 WS 16/17 15 [34]

Effizienzaspekte

I ZurVerbesserungder Effizienz:

IAnalyse derAuswertungsstrategie

I. . . und desSpeichermanagement

I Der ewige Konflikt:Geschwindigkeitvs.Platz I Effizenzverbesserungen durch

IEndrekursion: Iteration in funktionalen Sprachen

IStriktheit:Speicherlecksvermeiden (bei verzögerter Auswertung) I Vorteil: Effizienzmuss nichtim Vordergrund stehen

PI3 WS 16/17 16 [34]

(3)

Endrekursion

Definition (Endrekursion) Eine Funktion istendrekursiv, wenn

(i) es genaueinenrekursiven Aufruf gibt,

(ii) dernichtinnerhalb einesgeschachtelten Ausdruckssteht.

I D.h. darübernur Fallunterscheidungen:caseoderi f I Entsprichtgotooderwhilein imperativen Sprachen.

I Wird inSprungoderSchleifeübersetzt.

I Brauchtkeinen Platzauf dem Stack.

PI3 WS 16/17 17 [34]

Einfaches Beispiel

I In Haskell:

even x =i f x>1 theneven (x−2) else x == 0 I Übersetzt nach C:

int even (int x)

{ i f (x>1) return (even (x−2)) else return x == 0; } I Äquivalente Formulierung:

int x ; int even ()

{ i f (x>1) { x−= 2; return even ( ) ; } return x == 0; }

I Iterative Variante mit Schleife:

intx ; int even () { while (x>1) { x−= 2; }

return x == 0; }

PI3 WS 16/17 18 [34]

Beispiel: Fakultät

I Fakultätnichtendrekursiv:

fac1 :: Integer→ Integer

fac1 n =i f n == 0 then1 elsen∗ fac1 (n−1) I Fakultät endrekursiv:

fac2 :: Integer→ Integer fac2 n = fac ’ n 1where

fac ’ :: Integer→ Integer→ Integer fac ’ n acc =i f n == 0then acc

else fac ’ (n−1) (n∗acc) I fac1verbraucht Stack,fac2nicht.

I Istnichtmerklich schneller?!

PI3 WS 16/17 19 [34]

Beispiel: Listen umdrehen

I Liste umdrehen,nichtendrekursiv:

rev ’ :: [ a ]→ [ a ] rev ’ [ ] = [ ]

rev ’ (x : xs ) = rev ’ xs ++ [ x ]

IHängt auch nochhintenan —O(n2)!

I Liste umdrehen,endrekursivundO(n):

rev :: [ a ]→ [ a ]

rev xs = rev0 xs [ ] where rev0 [ ] ys = ys

rev0 (x : xs ) ys = rev0 xs (x : ys ) I Beispiel:last (rev [1..10000]) I Schneller— warum?

PI3 WS 16/17 20 [34]

Verzögerte Auswertung und Speicherlecks

I Garbage collectiongibtunbenutztenSpeicher wieder frei.

I Unbenutzt: Bezeichner nicht mehr imerreichbar

I Verzögerte Auswertungeffizient, weil nur beiBedarfausgewertet wird

I Aber Achtung:Speicherlecks!

I Eine Funktion hat einSpeicherleck, wenn Speicherunnötiglange im Zugriff bleibt.

I “Echte” Speicherlecks wie in C/C++nicht möglich.

I Beispiel:fac2

I Zwischenergebnisse werdennicht auswertet.

I Insbesondere ärgerlich beinicht-terminierenden Funktionen.

PI3 WS 16/17 21 [34]

Striktheit

I Strikte Argumenteerlauben AuswertungvorAufruf

IDadurchkonstanterPlatz beiEndrekursion.

I ErzwungeneStriktheit:seq :: α→β→β

⊥‘seq‘ b = ⊥ a ‘seq‘ b = b

I seqvordefiniert (nichtinHaskell definierbar)

I ($!) :: (a→b)→a→bstrikte Funktionsanwendung f $ ! x = x ‘ seq ‘ f x

Ighc machtStriktheitsanalyse I Fakultät in konstantem Platzaufwand

fac3 :: Integer→ Integer fac3 n = fac ’ n 1where

fac ’ n acc = seq acc $ i f n == 0then acc else fac ’ (n−1) (n∗acc)

PI3 WS 16/17 22 [34]

Speicherprofil: fac1 50000, nicht optimiert

fac 1 50000 +RTS -hc 108,438 bytes x seconds Tue Nov 22 15:24 2016

seconds 0.0 0.0 0.0 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.2 0.2

bytes

0k 200k 400k 600k

(52)PINNED (101)fac1/main/Main.CAF

Speicherprofil: fac1 50000, optimiert

fac 1 50000 +RTS -hc 64,778 bytes x seconds Tue Nov 22 15:24 2016

seconds

0.0 0.0 0.0 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.2 0.2

bytes

0k 50k 100k 150k 200k 250k 300k 350k

(52)PINNED (102)fac1/main

(4)

Speicherprofil: fac2 50000, nicht optimiert

fac 2 50000 +RTS -hc 126,365 bytes x seconds Tue Nov 22 15:24 2016

seconds

0.0 0.1 0.1 0.2 0.2 0.2

bytes

0k 200k 400k 600k

(52)PINNED (101)fac2/main/Main.CAF

PI3 WS 16/17 25 [34]

Speicherprofil: fac2 50000, optimiert

fac 2 50000 +RTS -hc 25,634 bytes x seconds Tue Nov 22 15:24 2016

seconds

0.0 0.1 0.1 0.2 0.2 0.2

bytes

0k 20k 40k 60k 80k 100k

(85)GHC.Conc.Signal.CAF (93)GHC.IO.Handle.FD.CAF (84)GHC.IO.Encoding.CAF (52)PINNED (102)fac2/main

PI3 WS 16/17 26 [34]

Speicherprofil: fac3 50000, nicht optimiert

fac 3 50000 +RTS -hc 26,525 bytes x seconds Tue Nov 22 15:24 2016

seconds

0.0 0.1 0.1 0.2 0.2 0.2 0.3

bytes

0k 20k 40k 60k 80k 100k

(89)GHC.Conc.Signal.CAF (86)GHC.IO.Handle.FD.CAF (87)GHC.IO.Encoding.CAF (52)PINNED (101)fac3/main/Main.CAF

PI3 WS 16/17 27 [34]

Speicherprofil: fac3 50000, optimiert

fac 3 50000 +RTS -hc 26,855 bytes x seconds Tue Nov 22 15:24 2016

seconds

0.0 0.1 0.1 0.2 0.2 0.2 0.3

bytes

0k 20k 40k 60k 80k 100k

(85)GHC.Conc.Signal.CAF (93)GHC.IO.Handle.FD.CAF (84)GHC.IO.Encoding.CAF (52)PINNED (102)fac3/main

PI3 WS 16/17 28 [34]

Fazit Speicherprofile

I Endrekursionnurbeistrikten Funktionenschneller I Optimierung desghc

I MeistausreichendfürStriktheitsanalyse

I Abernichtfür Endrekursion I Deshalb:

I ManuelleÜberführung in Endrekursionsinnvoll

I Compiler-Optimierungfür Striktheit nutzen

PI3 WS 16/17 29 [34]

Überführung in Endrekursion

I Voraussetzung 1: Funktion istlinear rekursiv

I Gegeben Funktion f0:ST

f0x = ifB x thenH x

else(f0(K x))⊗ (E x)

IMitK:SS,⊗:TTT,E:ST,H:ST.

I Voraussetzung 2:⊗assoziativ,e:T neutrales Element

I Dann istendrekursiveForm:

f:ST

f x = g x ewhere

g x y = ifB x then(H x)⊗y elseg(K x) ((E x)⊗y)

PI3 WS 16/17 30 [34]

Beispiel

I Länge einer Liste (nicht-endrekursiv) length ’ :: [α]→ Int

length ’ xs =i f n u l l xs then0 else 1+ length ’ ( t a i l xs )

I Zuordnung der Variablen:

K(x) 7→ tailx E(x) 7→ 1 xy 7→ x+y

B(x) 7→ nullx H(x) 7→ 0

e 7→ 0 I Es gilt:x⊗e=x+ 0 =x (0 neutrales Element)

PI3 WS 16/17 31 [34]

Beispiel

I DamitendrekursiveVariante:

length :: [α]→ Int length xs = len xs 0where

len xs y = i f n u l l xs then y−−was: y+ 0 else len ( t a i l xs ) (1+ y)

I AllgemeinesMuster:

IMonoid (⊗,e):⊗assoziativ,eneutrales Element.

IZusätzlicher ParameterakkumuliertResultat.

PI3 WS 16/17 32 [34]

(5)

Weiteres Beispiel: f o l d r vs. f o l d l

I f o l d ristnicht endrekursiv:

f o l d r :: (α→ββ)β → [α] →β f o l d r f z [ ] = z

f o l d r f z (x : xs ) = f x ( f o l d r f z xs ) I f o l d listendrekursiv:

f o l d l :: (α→βα)α→ [β] →α f o l d l f z [ ] = z

f o l d l f z (x : xs ) = f o l d l f ( f z x) xs I f o l d l ’iststriktundendrekursiv:

f o l d l ’ :: (α→β→α)→α→ [β]→α f o l d l ’ f a [ ] = a

f o l d l ’ f a (x : xs ) =let a0= f a x in a0 ‘ seq ‘ f o l d l ’ f a0 xs I Für Monoid (⊗,e) gilt:f o l d r⊗e l=f o l d l ( f l i p ⊗) e l

PI3 WS 16/17 33 [34]

Zusammenfassung

Imapundfoldsind kanonische Funktionen höherer Ordnung, und für alle Datentypen definierbar

Imap,f i l t e r,foldsind ein nützliches, skalierbares und allgemeines Berechnungsmuster

I Effizient funktional programmieren:

IEndrekursion:whilefür Haskell

IMitStriktheitundEndrekursionSpeicherlecksvermeiden.

IFür StriktheitCompileroptimierungnutzen

I Nächste Woche: Funktionale Programmierung im Großen — Abstrakte Datentypen

PI3 WS 16/17 34 [34]

Referenzen

ÄHNLICHE DOKUMENTE

I Für funktionale Programme: rekursiv definierte Funktionen.. Äquivalenz von operationaler und

I Funktionen höherer Ordnung II und Effizenzaspekte I Teil II: Funktionale Programmierung im Großen I Teil III: Funktionale Programmierung im richtigen Leben. PI3 WS 16/17

Praktische Informatik 3: Funktionale Programmierung Vorlesung 5 vom 15.11.2016: Funktionen Höherer Ordnung I..

I Funktionen höherer Ordnung II und Effizenzaspekte I Teil II: Funktionale Programmierung im Großen I Teil III: Funktionale Programmierung im richtigen Leben.. PI3 WS 16/17

Praktische Informatik 3: Funktionale Programmierung Vorlesung 2 vom 21.10.2014: Funktionen und Datentypen..

Praktische Informatik 3: Funktionale Programmierung Vorlesung 5 vom 11.11.2014: Funktionen Höherer Ordnung I..

Praktische Informatik 3: Funktionale Programmierung Vorlesung 5 vom 11.11.2014: Funktionen Höherer Ordnung I.. Christoph Lüth Universität Bremen

Praktische Informatik 3: Funktionale Programmierung Vorlesung 6 vom 18.11.2014: Funktionen Höherer Ordnung II..