• Keine Ergebnisse gefunden

Einfaches Beispiel

N/A
N/A
Protected

Academic year: 2022

Aktie "Einfaches Beispiel"

Copied!
4
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Praktische Informatik 3: Funktionale Programmierung Vorlesung 12 vom 15.01.2013: Effizienzaspekte

Christoph Lüth Universität Bremen Wintersemester 2012/13

Rev. 1980 1 [31]

Fahrplan

I Teil I: Funktionale Programmierung im Kleinen

I Teil II: Funktionale Programmierung im Großen

I Teil III: Funktionale Programmierung im richtigen Leben

IEffizienzaspekte

IEine Einführung in Scala

IRückblich & Ausblick

2 [31]

Inhalt

I Zeitbedarf:Endrekursion—whilein Haskell I Platzbedarf:Speicherlecks

I “Unendliche” Datenstrukturen I Verschiedene anderePerformancefallen:

I ÜberladeneFunktionen,Listen I “Usual Disclaimers Apply”:

I Erste Lösung: bessereAlgorithmen

I Zweite Lösung:Büchereiennutzen

3 [31]

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

4 [31]

Endrekursion

Definition (Endrekursion) Eine Funktion istendrekursiv, wenn

(i) es genaueinenrekursiven Aufruf gibt,

(ii) dernichtinnerhalb einesgeschachtelten Ausdruckssteht.

I D.h. darübernur Fallunterscheidungen:caseoderif

I Entsprichtgotooderwhilein imperativen Sprachen.

I Wird inSprungoderSchleifeübersetzt.

I Brauchtkeinen Platzauf dem Stack.

5 [31]

Einfaches Beispiel

I In Haskell:

e v e n x = i f x< 1 then x == 0 e l s e e v e n ( x−2) I Übersetzt nach C:

i n t e v e n (i n t x )

{ i f ( x<1 ) r e t u r n x == 0 ; e l s e r e t u r n ( e v e n ( x−2 ) ) ; } I Äquivalente Formulierung:

i n t e v e n (i n t x )

{ i f ( x< 1 ) r e t u r n x == 0 ;

e l s e { x −= 2 ; r e t u r n e v e n ( x ) ; } } I Iterative Variante mit Schleife:

i n t e v e n (i n t x )

{ w h i l e ( ! ( x<1 ) ) x −= 2 ; r e t u r n x == 0 ; }

6 [31]

Beispiel: Fakultät

I fac1nichtendrekursiv:

f a c 1 :: I n t e g e r→ I n t e g e r

f a c 1 n = i f n == 0 then 1 e l s e n ∗ f a c 1 ( n−1)

I fac2endrekursiv:

f a c 2 :: I n t e g e r→ I n t e g e r

f a c 2 n = f a c ’ n 1 where

f a c ’ :: I n t e g e r→ I n t e g e r→ I n t e g e r f a c ’ n a c c = i f n == 0 then a c c

e l s e f a c ’ ( n−1) ( n∗a c c ) I fac1verbraucht Stack,fac2nicht.

7 [31]

Beispiel: Listen umdrehen

I Liste umdrehen,nichtendrekursiv:

r e v ’ :: [ a ]→ [ a ]

r e v ’ [ ] = [ ]

r e v ’ ( x : x s ) = r e v ’ x s ++ [ x ]

IHängt auch nochhintenan —O(n2)!

I Liste umdrehen,endrekursivundO(n):

r e v :: [ a ]→ [ a ]

r e v x s = r e v 0 x s [ ] where r e v 0 [ ] y s = y s

r e v 0 ( x : x s ) y s = r e v 0 x s ( x : y s ) I Beispiel:last (rev [1..10000])

8 [31]

(2)

Überführung in Endrekursion

I Gegeben Funktion f0:ST

f0x = ifB x thenH x

elseφ(f0(K x)) (E x)

I MitK:SS,φ:TTT,E:ST,H:ST.

I Voraussetzung:φ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)

9 [31]

Beispiel

I Länge einer Liste (nicht-endrekursiv)

l e n g t h ’ :: [ a ]→ I n t

l e n g t h ’ x s = i f n u l l x s then 0

e l s e 1+ l e n g t h ’ ( t a i l x s )

I Zuordnung der Variablen:

K(x) 7→ tailx E(x) 7→ 1 φ(x,y) 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)

10 [31]

Beispiel

I DamitendrekursiveVariante:

l e n g t h :: [ a ]→ I n t l e n g t h x s = l e n x s 0 where

l e n x s y = i f n u l l x s then y−−was: y+ 0 e l s e l e n ( t a i l x s ) ( 1+ y )

I AllgemeinesMuster:

I Monoid(φ,e):φassoziativ,eneutrales Element.

I Zusätzlicher ParameterakkumuliertResultat.

11 [31]

Endrekursive Aktionen

I Nicht endrekursiv:

g e t L i n e s ’ :: IO S t r i n g g e t L i n e s ’ = do s t r← g e t L i n e

i f n u l l s t r then r e t u r n " "

e l s e do r e s t← g e t L i n e s ’ r e t u r n ( s t r++ r e s t )

I Endrekursiv:

g e t L i n e s :: IO S t r i n g g e t L i n e s = g e t i t " " where

g e t i t r e s = do s t r← g e t L i n e

i f n u l l s t r then r e t u r n r e s e l s e g e t i t ( r e s++ s t r )

12 [31]

Fortgeschrittene Endrekursion

I Akkumulationvon Ergebniswerten durchclosures

I closure: partiell applizierte Funktion I Beispiel: die KlasseShow

I Nur Methodeshowwäre zu langsam (O(n2)):

c l a s s Show a where show :: a→ S t r i n g

I Deshalb zusätzlich

s h o w s P r e c :: I n t→ a→ S t r i n g→ S t r i n g show x= s h o w s P r e c 0 x " "

I String wird erst aufgebaut, wenn er ausgewertet wird (O(n)).

13 [31]

Beispiel: Mengen als Listen

data S e t a = S e t [ a ] Zulangsamwäre

i n s t a n c e Show a⇒ Show ( S e t a ) where show ( S e t e l e m s ) =

" { " ++ i n t e r c a l a t e " , " ( map show e l e m s ) ++ " } "

Deshalbbesser

i n s t a n c e Show a⇒ Show ( S e t a ) where

s h o w s P r e c i ( S e t e l e m s ) = showElems e l e m s where showElems [ ] = ( " {} " ++)

showElems ( x : x s ) = ( ’ { ’ : ) ◦s h o w s x◦s h o w l x s where s h o w l [ ] = ( ’ } ’ : )

s h o w l ( x : x s ) = ( ’ , ’ : ) ◦s h o w s x◦s h o w l x s

14 [31]

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:getLines,fac2

I Zwischenergebnisse werdennicht auswertet.

I Insbesondere ärgerlich beinicht-terminierenden Funktionen.

15 [31]

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 ‘ s e q ‘ f x

Ighc machtStriktheitsanalyse I Fakultät in konstantem Platzaufwand

f a c 3 :: I n t e g e r→ I n t e g e r f a c 3 n = f a c ’ n 1 where

f a c ’ n a c c = s e q a c c $ i f n == 0 then a c c e l s e f a c ’ ( n−1) ( n∗a c c )

16 [31]

(3)

Speicherprofil: fac1 50000, nicht optimiert

fac 1 50000 +RTS -hc (null) 228,418 bytes x seconds Tue Jan 15 13:28 2013

seconds

0.0 0.2 0.4 0.6 0.8

bytes

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

(51)PINNED (99)fac1/main/Main.CAF

17 [31]

Speicherprofil: fac2 50000, nicht optimiert

fac 2 50000 +RTS -hc (null) 253,330 bytes x seconds Tue Jan 15 13:28 2013

seconds

0.0 0.2 0.4 0.6 0.8 1.0

bytes

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

(51)PINNED (99)fac2/main/Main.CAF

18 [31]

Speicherprofil: fac3 50000, nicht optimiert

fac 3 50000 +RTS -hc (null) 85,428 bytes x seconds Tue Jan 15 13:29 2013

seconds

0.0 0.2 0.4 0.6 0.8

bytes

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

(93)GHC.IO.Encoding.CAF (51)PINNED (99)fac3/main/Main.CAF

19 [31]

Speicherprofil: fac1 50000, optimiert

fac 1 50000 +RTS -hc (null) 179,641 bytes x seconds Tue Jan 15 13:29 2013

seconds

0.0 0.2 0.4 0.6 0.8

bytes

0k 50k 100k 150k 200k 250k

(50)PINNED (98)fac1/main

20 [31]

Speicherprofil: fac2 50000, optimiert

fac 2 50000 +RTS -hc (null) 90,657 bytes x seconds Tue Jan 15 13:29 2013

seconds

0.0 0.2 0.4 0.6 0.8

bytes

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

(88)GHC.IO.Encoding.CAF (50)PINNED (98)fac2/main

21 [31]

Speicherprofil: fac3 50000, optimiert

fac 3 50000 +RTS -hc (null) 85,464 bytes x seconds Tue Jan 15 13:29 2013

seconds

0.0 0.2 0.4 0.6 0.8

bytes

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

(88)GHC.IO.Encoding.CAF (50)PINNED (98)fac3/main

22 [31]

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

23 [31]

foldr vs. foldl

I foldristnicht endrekursiv:

f o l d r :: ( a → b → b ) → b → [ a ] → b

f o l d r f z [ ] = z

f o l d r f z ( x : x s ) = f x ( f o l d r f z x s ) I foldlistendrekursiv:

f o l d l :: ( a → b → a ) → a → [ b ] → a

f o l d l f z [ ] = z

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

f o l d l ’ :: ( a→ b→ a )→ a→ [ b ]→ a

f o l d l ’ f a [ ] = a

f o l d l ’ f a ( x : x s ) =

l e t a ’ = f a x i n a ’ ‘ s e q ‘ f o l d l ’ f a ’ x s I Für Monoid(φ,e)gilt:foldrφe l=foldl(flipφ)e l

24 [31]

(4)

Wann welches fold?

I foldlendrekursiv, aber traversiert immer dieganzeListe.

I foldl’fernerstriktundkonstanter Platzaufwand I Wann welchesfold?

I Strikte Funktionenmitfoldl’falten:

r e v 2 :: [ a ]→ [ a ]

r e v 2 = f o l d l ’ ( f l i p ( : ) ) [ ]

I Wennnicht die ganze Listebenötigt wird, mitfoldrfalten:

a l l :: ( a→ B o o l )→ [ a ]→ B o o l a l l p = f o l d r ((&&)◦p ) True

I PotenziellunendlicheListenimmermitfoldrfalten.

25 [31]

Effizienz durch “unendliche” Datenstrukturen

I Listen müssen nichtendlich repräsentierbarsein:

INützlichfür Listen mitunbekannter Länge

IObacht:Induktion nur fürendlicheListen gültig.

I Beispiel: Fibonacci-Zahlen

IAus der Kaninchenzucht.

ISollte jeder Informatiker kennen.

f i b ’ :: I n t→ I n t e g e r f i b ’ 0 =1

f i b ’ 1 =1

f i b ’ n = f i b ’ ( n−1)+ f i b ’ ( n−2)

IProblem:baumartigeRekursion,exponentiellerAufwand.

26 [31]

Fibonacci-Zahlen als Strom

I Lösung: zuvor berechneteTeilergebnisse wiederverwenden.

I Seifibs :: [ Integer ]Strom aller Fibonaccizahlen:

f i b s 1 1 2 3 5 8 13 21 34 55

t a i l f i b s 1 2 3 5 8 13 21 34 55

t a i l ( t a i l f i b s ) 2 3 5 8 13 21 34 55

I Damit ergibt sich:

f i b s :: [ I n t e g e r ]

f i b s = 1 : 1 : z i p W i t h (+) f i b s ( t a i l f i b s )

I n-te Fibonaccizahl mitfibs !! n

I Aufwand:linear, dafibs nur einmal ausgewertet wird.

27 [31]

Implementation und Repräsentation von Datenstrukturen

I Datenstrukturen werden intern durchObjektein einemHeap repräsentiert

I Bezeichner werden anReferenzenin diesen Heap gebunden I Unendliche Datenstrukturen haben zyklische Verweise

IKopf wird nureinmalausgewertet.

c y c l e ( t r a c e " Foo ! " [ 5 ] )

I Anmerkung: unendlich Datenstrukturen nur sinnvoll fürnicht-strikte Funktionen

28 [31]

Überladene Funktionen sind langsam.

I Typklassen sind elegant aberlangsam.

I Implementierung von Typklassen:Verzeichnis(dictionary) von Klassenfunktionen.

I Überladung wird zurLaufzeitaufgelöst

I Bei kritischen Funktionen:Spezialisierung erzwingendurch Angabe der Signatur

I NB:Zahlen(numerische Literale) sind in Haskellüberladen!

I Bsp:facshat den TypNum a=> a-> a

f a c s n= i f n == 0 then 1 e l s e n∗ f a c s ( n−1)

29 [31]

Listen als Performance-Falle

I Listen sindkeineFelder oder endliche Abbildungen I Listen:

IBeliebiglang

IZugriff aufn-tes Element inlinearerZeit (O(n))

IAbstrakt: frei erzeugter Datentyp aus Kopf und Rest

I FelderArray ix a(ModulArrayaus der Standardbücherei )

IFesteGröße (Untermenge vonix)

IZugriff aufn-tes Element inkonstanterZeit(O(1))

IAbstrakt: Abbildung Index auf Daten

I Endliche AbbildungMap k v(ModulData.Map)

IBeliebige Größe

IZugriff aufn-tes Element insublinearerZeit (O(logn))

IAbstrakt: Abbildung Schlüsselbereichkauf Wertebereichv

ISonderfall:Set k≡Map k Bool

30 [31]

Zusammenfassung

I Endrekursion:whilefür Haskell.

I Überführung in Endrekursionmeist möglich.

I Noch besser sindstrikte Funktionen.

I Speicherlecksvermeiden:StriktheitundEndrekursion I Compileroptimierungnutzen

I Datenstrukturen müssen nichtendlich repräsentierbarsein I Überladene Funktionensind langsam.

I Listensind keine Felder oder endliche Abbildungen.

31 [31]

Referenzen

ÄHNLICHE DOKUMENTE

Praktische Informatik 3: Funktionale Programmierung Vorlesung 3 vom 28.10.2014: Rekursive Datentypen.. Christoph Lüth Universität Bremen

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.. Christoph Lüth Universität Bremen

Praktische Informatik 3: Funktionale Programmierung Vorlesung 9 vom 09.12.2012: Signaturen und Eigenschaften.. Christoph Lüth Universität Bremen

Praktische Informatik 3: Funktionale Programmierung Vorlesung 11 vom 06.01.2015: Aktionen und Zustände.. Christoph Lüth Universität Bremen

I Verzögerte Auswertung effizient, weil nur bei Bedarf ausgewertet wird.. I Aber

Praktische Informatik 3: Funktionale Programmierung Vorlesung 13 vom 20.01.15: Scala — Eine praktische Einführung.. Christoph Lüth Universität Bremen

Praktische Informatik 3: Funktionale Programmierung Vorlesung 3 vom 30.10.2012: Rekursive Datentypen.. Christoph Lüth Universität Bremen