• Keine Ergebnisse gefunden

R¨ uckblick Haskell

N/A
N/A
Protected

Academic year: 2022

Aktie "R¨ uckblick Haskell"

Copied!
40
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Fortgeschrittene Techniken der Funktionalen Programmierung Vorlesung vom 20.10.09:

Einf¨uhrung und R¨uckblick

Christoph L¨uth, Dennis Walter Universit¨at Bremen Wintersemester 2009/10

1

Organisatorisches

IVorlesung: Di 8 – 10 MZH 7250

I ¨Ubung: Do 10 – 12 MZH 7210 (nach Bedarf) IScheinkriterien:

I 5 ¨Ubungsbl¨atter

I Alle bearbeitet, insgesamt 40% (Notenspiegel PI3)

I ¨Ubungsgruppen 2 – 4 Mitglieder

I Ggf. Fachgespr¨ach am Ende

2

Warum?

IHaskell: Nicht nur f¨ur¨Ubungsaufgaben

IFunktionale Sprachen sindInnovationsinkubatoren

IFunktionale Sprachen behandeln Zukunftsthemenheute

3

Themen

IMonaden undfortgeschrittene Typen

I Was ist eine ”Monade”?

I IOund andere Monaden

I Konstruktorklassen, Rang-2-Polymorphie IFortgeschritteneDatenstrukturen

I Der Zipper

I Str¨ome, Graphen, unendliche Datenstrukturen INebenl¨aufigkeit

I Leichtgewichte Threads in Haskell

I Queues, Semaphoren, Monitore . . .

I State Transactional Memory ITheFutureof Programming

I Dom¨anenspezifische Sprachen (DSLs)

I Fancy Types

I The Next Big Thing: F#, Scala

4

Ressourcen

IHaskell-Webseite:http://www.haskell.org/

IB¨uchereien:

IHaskell 98 Libraries

IHaskell Hierarchical Libraries ICompiler:

IGlasgow Haskell Compiler (ghc) (Version 6.10)

Ihttp://www.haskell.org/ghc/

IB¨ucher und Artikel

ISiehe

http://www.informatik.uni-bremen.de/˜cxl/lehre/asp.ws09/

IAbmorgen!

5

R¨ uckblick Haskell

IDefinition von Funktionen:

I lokale Definitionen mitletundwhere

I Fallunterscheidung undguarded equations

I Abseitsregel

I Funktionen h¨oherer Ordnung ITypen:

I Basisdatentypen:Int,Integer,Rational,Double,Char,Bool

I Strukturierte Datentypen:[a],(a, b)

I Algebraische Datentypem:data Maybe a = Just a — Nothing

6

R¨ uckblick Haskell

IAbstrakte Datentypen

IModule

ITypklassen

IVerz¨ogerte Auswertung und unendliche Datentypen

7

I/O in funktionalen Sprachen

IProblem:Eingabe kann nicht als Funktion r e a d L i n e : : ( ) S t r i n g

modelliert werden — zerst¨ortreferentielle Transparenz.

IGenerelles Problem hier:Interaktion mit der Umwelt IM¨ogliche L¨osungen:

I Seiteneffekte (e.g. Standard ML);

I Continuations (Auswertungskontext explizit modellieren);

I Streams:readLine :: Instream-¿ (Instream, String)

I Einkapselung inMonaden(Haskell).

8

(2)

Monadische I/O

IAbstrakter DatentypIO a:

(=) : : IO t ( t IO u ) IO u −−“then”

r e t u r n : : t IO t −−“return”

I t :: IO aerst eine Aktion, gibt dann Wert vom Typazur¨uck:

type IO a = World ( a , World )

9

Monadische I/O

IElementare Operationen:

g e t L i n e : : IO S t r i n g −−eine Zeile lesen p u t S t r : : S t r i n g IO ( ) −−Zeile ausgeben putStrLn : : S t r i n g IO ( ) −−Zeile mit LF ausgeben

I“Einmal I/O, immer I/O”

IAbh¨angigkeit von Umwelt am Typ erkennbar

IDaher:

main : : IO ( )

Hauptprogramm hat keinen R¨uckgabewert, nur noch Interaktion.

10

Monadische I/O: Die do Notation

ISyntaktischer Zucker f¨ur Monaden:

echo =

do s g e t L i n e g e t L i n e

putStrLn s ←→ =λs putStrLn s

echo echo

IOder auch:

echo = do { s g e t L i n e ; putStrLn s ; echo } IN¨utzlich:

() : : IO t IO u IO u

f g f g

11

Monadische I/O: Einfache Beispiele

echo : : IO ( )

echo = g e t L i n e =putStrLn echo

echo = do { l g e t L i n e ; putStrLn l ; echo } i n t e r a c t O n c e : : ( S t r i n g S t r i n g ) IO ( ) i n t e r a c t O n c e f = g e t L i n e =( p u t S t r . f )

i n t e r a c t O n c e f = do { l g e t L i n e ; putStrLn ( f l ) } r e v e ch o : : IO ( )

r e v e ch o = g e t L i n e =putStrLn . r e v e r s e r e v ec h o

r e v e ch o = do { l g e t L i n e ; putStrLn ( r e v e r s e l ) ; r e v e c h o }

12

File I/O

Abstrakter Zugriff durchlazy evaluation:

type F i l e P a t h = S t r i n g g e t C o n t e n t s : : IO S t r i n g

r e a d F i l e : : F i l e P a t h IO S t r i n g w r i t e F i l e : : F i l e P a t h S t r i n g IO ( ) a p p e n d F i l e : : F i l e P a t h S t r i n g IO ( ) Beispiel:

cntWords : : F i l e P a t h IO ( ) cntWords f i l e = do c r e a d F i l e f i l e

l e t s = ( l e n g t h . words ) c

p u t S t r $ f i l e++ ” : ”++ show s++ ” wordsλn”

13

Fortgeschrittene File I/O

data IOMode = ReadMode | WriteMode | AppendMode

o p e n F i l e : : F i l e P a t h IOMode IO Handle hGetContents : : Handle IO S t r i n g −−uvm.

hFlush : : Handle IO ( )

hGetPosn : : Handle IO HandlePosn

hSetPosn : : HandlePosn IO ( )

data SeekMode = AbsoluteSeek | R e l a t i v e S e e k | SeekFromEnd

hSeek : : Handle SeekMode I n t e g e r IO ( )

Weitere ¨ubliche Operationen (Buffering etc) sieheHaskell98 Library Report, Kap. 11.

14

Fehler!

Repr¨asentation durch den abstrakten DatentypIOError. Ausnahmebehandlung ¨ahnlich in Java:

i o E r r o r : : I O E r r o r IO a

catch : : IO a ( I O E r r o r IO a ) IO a Beispiel:

cntW f i l e = catch ( cntWords f i l e )

(λe→ p u t S t r ( ” E r r o r : ” ++ ( show e ) ) ) Analyse der Fehler durchisDoesNotExistsError :: IOError-¿ Bool

etc.

Kommandozeilenargumente

Interaktion mit der Umgebung: ModulSystem

data ExitCode = E x i t S u c c e s s | E x i t F a i l u r e I n t getArgs : : IO [ S t r i n g ]

getProgName : : IO S t r i n g

getEnv : : S t r i n g IO S t r i n g

system : : S t r i n g IO ExitCode

e x i t W i t h : : ExitCode IO a Beispiel:

main =do rgetProgName ; a getArgs catch (mapM cntWords a )

(λe→ putStrLn ( r++ ” : ”++ ( show e ) ) )

(3)

Das Modul Directory

c r e a t e D i r e c t o r y : : F i l e P a t h IO ( ) removeDirectory , r e m o v e F i l e : : F i l e P a t h IO ( ) renameDirectory , r e n a m e F i l e : : F i l e P a t h F i l e P a t h IO ( )

g e t D i r e c t o r y C o n t e n t s : : F i l e P a t h IO [ F i l e P a t h ] g e t C u r r e n t D i r e c t o r y : : IO F i l e P a t h

s e t C u r r e n t D i r e c t o r y : : F i l e P a t h IO ( ) data P e r m i s s i o n s = . . .

r e a d a b l e , w r i t e a b l e , e x e c u t a b l e , s e a r c h a b l e : : P e r m i s s i o n s Bool g e t P e r m i s s i o n s : : F i l e P a t h IO P e r m i s s i o n s

s e t P e r m i s s i o n s : : F i l e P a t h P e r m i s s i o n s IO ( ) g e t M o d i f i c a t i o n T i m e : : F i l e P a t h IO ClockTime

17

Das Modul Directory, Beispiel

import D i r e c t o r y import Time

import System ( getArgs ) c l e a nu p d i r =

do now←getClockTime

c g e t D i r e c t o r y C o n t e n t s d i r s e t C u r r e n t D i r e c t o r y d i r

mapM (λf do {mt g e t M o d i f i c a t i o n T i m e f ; i f ( ( l a s t f ’ ˜ ’ ) &&

tdDay ( d i f f C l o c k T i m e s mt now ) 1)

then r e m o v e F i l e f e l s e r e t u r n ( )}) c main =do { d getArgs ; c l ea n u p ( head d ) }

18

Systemfunktionen f¨ ur Haskell

IAbstrakte Modellierung inHaskell98 Standard Library:

IO,Directory System,Time SieheLibrary Report

IKonkrete Modellierung in ModulPosix(nur f¨urGHC) nach IEEE Standard 1003.1, e.g.:

e x e c u t e F i l e : : F i l e P a t h −−Command

Bool −−Search

PATH?

[ S t r i n g ] −−Arguments

Maybe [ ( S t r i n g , S t r i n g ) ] −−Environ- ment

IO ( )

19

More IO

N¨utzliche Kombinatoren (aus demPrelude):

sequence : : [ IO a ] IO [ a ] s e q u e n c e : : [ IO a ] IO ( )

mapM : : ( a IO b ) [ a ] IO [ b ]

mapM : : ( a IO b ) [ a ] IO ( )

Mehr im ModulMonad(Library Report, Kapt. 10).

20

Zusammenfassung

IAbh¨angigkeit von Aussenwelt in TypIOkenntlich

IBenutzung von IO: vordefinierte Funktionen in der Haskell98 B¨ucherei

IN¨achstes Mal:

IWas steckt dahinter?

IFlucht aus Alcatraz – IO f¨ur Erwachsene

IEndlich Variablen

21

(4)

Fortgeschrittene Techniken der Funktionalen Programmierung Vorlesung vom 27.10.09:

Monads — The Inside Story

Christoph L¨uth, Dennis Walter Universit¨at Bremen Wintersemester 2009/10

1

Heute in diesem Theater

IDie Geheimnisse der Monaden

IEndlich Zuweisungen

IFlucht aus Alcatraz –IOf¨ur Erwachsene

2

Fahrplan

ITeil I: Monaden und fortgeschrittene Typen

IEinf¨uhrung, Wiederholung

IZust¨ande, Zustands¨uberg¨ange undIO

IReader/Writer, Nichtdeterminismus, Ausnahmen

IMonadentransformer

ITeil II: Fortgeschrittene Datenstrukturen ITeil III: Nebenl¨aufigkeit

ITeil IV: The Future of Programming

3

Zustands¨ ubergangsmonaden

IAktionen (IO a) sind keine schwarze Magie.

IGrundprinzip: SystemzustandΣwird explizit behandelt.

f :: aIO b = f :: (a, Σ)(b,Σ) FolgendeInvariantenm¨ussen gelten:

I Systemzustand darfnie dupliziertodervergessenwerden.

I Auswertungsreihenfolge muß erhalten bleiben.

IKompositionmussInvariantenerhalten Zustands¨ubergangsmonaden

4

Zustands¨ ubergangsmonaden

ITyp:

type ST s a = s ( a , s )

a ST s b=as(b, s)=(a, s)(b, s) Parametrisiert ¨uber Zustandsund Berechnungswerta.

IKomposition durch

(=) : : ST s a ( a ST s b ) ST s b

5

Komposition von Zustands¨ uberg¨ angen

IIm Prinzip Vorw¨artskomposition:

(=) : : ST s a ( a ST s b ) ST s b

(=) : : ( s ( a , s ) ) ( a s ( b , s ) ) ( s ( b , s ) ) (=) : : ( s ( a , s ) ) ( ( a , s ) ( b , s ) ) ( s ( b , s ) )

IDamitf =g = uncurry g . f.

IAber:STkannkein Typsynonymsein

IN¨otig:abstrakter DatentypumInvariantenzu erhalten

6

ST als Abstrakter Datentyp

IDatentyp verkapseln:

newtype ST s a = ST ( s ( a , s ) ) IHilfsfunktion (Selektor)

unwrap : : ST s a ( s ( a , s ) ) unwrap (ST f ) = f

IDamit ergibt sich

f =g = ST ( u n c u r r y ( unwrap . g ) . unwrap f ) r e t u r n a = ST (λs ( a , s ) )

Aktionen

IAktionen: Zustandstransformationen auf der Welt ITypRealWorld#repr¨asentiert Außenwelt

I Typ hat genau einen Wertrealworld #, der nur f¨ur initialen Aufruf erzeugt wird.

I Aktionen:typeIO a = ST RealWorld# a IOptimierungen:

I ST s adurchin-place-updateimplementieren.

I IO-Aktionen durcheinfachen Aufrufersetzen.

I Compiler darf keine Redexe duplizieren!

I TypIOstelltlediglichReihenfolge sicher.

(5)

Was ist eigentlich eine Monade?

ISTmodelliertimperative Konzepte.

IBeobachtung:Andere Konzepte k¨onnen¨ahnlich modelliertwerden:

IAusnahmen:f :: a-¿ Maybe bmit Komposition (=) : : Maybe a ( a Maybe b ) Maybe b J u s t a =f = f a

Nothing=f = Nothing

IBen¨otigen Typklassen f¨ur Typkonstruktoren. . .

9

Konstruktorklassen

IKonstruktorklassen: Typklassen f¨ur Typkonstruktoren (kinds) IBeispiel:

c l a s s Functor f where

fmap : : ( a b ) ( f a f b )

i n s t a n c e Functor [ ] where −−Kein ’echtes’ Haskell!

fmap f [] = []

fmap f ( x : xs ) = f x : map f xs IErweiterungdes Typsystems (bleibtentscheidbar) IF¨ur ZustandstransformerST:

i n s t a n c e Monad (ST s ) where

f =g = ST ( u n c u r r y ( unwrap . g ) . unwrap f ) r e t u r n a = ST (λs→ ( a , s ) )

10

Monads: The Inside Story

c l a s s Monad m where

(=) : : m a ( a m b ) m b r e t u r n : : a m a

() : : m a m b m b f a i l : : S t r i n g m a pq = p=λ q

f a i l s = e r r o r s

FolgendeGleichungenm¨ussen (sollten)gelten:

return a=k = k a m=return = m

m=(λx→k x=h) = (m=k)=h

11

Beispiel: Speicher und Referenzen

ISignatur:

type Mem a

i n s t a n c e Mem Monad IReferenzen sind abstrakt:

type Ref

newRef : : Mem Ref

ISpeicher liest/schreibtString:

readRef : : Ref Mem S t r i n g w r i t e R e f : : Ref S t r i n g Mem ( )

12

Implementation der Referenzen

Speicher: Liste von Strings, Referenzen: Index in Liste.

type Mem = ST [ S t r i n g ] −−Zustand type Ref = I n t

newRef = ST (λs ( l e n g t h s , s++[ ”” ] ) ) readRef r = ST (λs ( s ! ! r , s ) ) w r i t e R e f r v = ST (λs ( ( ) ,

take r s ++ [ v ]++ drop ( r +1) s ) ) run : : Mem a a

run (ST f )= f s t ( f [] )

13

IORef — Referenzen

IDatentyp der Standardb¨ucherei (GHC, Hugs)

import Data . IORef data IORef a

newIORef : : a IO ( IORef a ) readIORef : : IORef a IO a w r i t e I O R e f : : IORef a a IO ( )

modifyIORef : : IORef a ( a a ) IO ( )

atomicModifyIORef : : IORef a ( a ( a , b ) ) IO b

IImplementation: “echte” Referenzen.

14

Beispiel: Referenzen

f a c : : I n t IO I n t

f a c x = do acc newIORef 1 loop acc x where

loop acc 0 = readIORef acc loop acc n = do t readIORef acc

w r i t e I O R e f acc ( t∗ n ) loop acc ( n1)

15

Flucht aus Alcatraz

IAus demIO-Monaden gibt es keinen Ausweg.

I Im Gegensatz zu z.B.Maybe:

fromMaybe : : a Maybe a a

IDas ist manchmal unpraktisch: Initialisierungen etc.

IF¨urSTgibt es

fixST : : ( a ST s a ) ST s a −−Fixpunkt runST : : (f o r a l l s . ST s a ) a −−NB: Typ!

IF¨urIOgibt es . . .

16

(6)

Unsichere Aktionen

ISignatur:

import System . IO . Unsafe ( unsafePerformIO ) unsafePerformIO : : IO a a

IWarnung: gef¨ahrlichund nichttypsicher!

t e s t : : IORef [ a ]

t e s t = unsafePerformIO $ newIORef []

main = do w r i t e I O R e f t e s t [ 4 2 ] bangreadIORef t e s t putStrLn ( bang : : [ Char ] )

17

Verwendung von unsafePerformIO

IIO-Aktionen, die nur

I einmaldurchgef¨uhrt werden sollen, und

I von anderen IO-Aktionenunabh¨angigsind

I Beispiel: Konfigurationsdatei lesen

IAlloziierungglobaler Ressourcen(z.B. Referenzen).

IDebugging(traces, logfiles).

IEnjoyresponsibly!

18

Benutzung von unsafePerformIO

IAlloziierung globaler Referenzen:

−−— Generate a new identifier.

newId : : IO I n t

newId = atomicModifyIORef r $ λi ( i +1, i ) where r = unsafePerformIO $ newIORef 1 {−# NOINLINE newId #−}

INOINLINEbeachten — Optimierungen verhindern.

IDebugging:

t r a c e : : S t r i n g a a

t r a c e s x = unsafePerformIO $ putStrLn s r e t u r n x

ISchon vordefiniert (Debug.Trace).

19

Zusammenfassung & Ausblick

IBlick hinter die Kulissen vonIO IMonaden und andere Kuriosit¨aten

IReferenzen

IunsafePerformIO

IN¨achstes Mal: Mehr Monaden. . .

20

(7)

Fortgeschrittene Techniken der Funktionalen Programmierung Vorlesung vom 03.11.09:

Mehr ¨uber Monaden

Christoph L¨uth, Dennis Walter Universit¨at Bremen Wintersemester 2009/10

1

Heute gibt’s:

IMonaden, mehrMonaden, und noch mehrMonaden

I Die Monaden der Standardb¨ucherei

I Referenz:http://www.haskell.org/all˙about˙monads/html

2

Fahrplan

ITeil I: Monaden und fortgeschrittene Typen

IEinf¨uhrung, Wiederholung

IZust¨ande, Zustands¨uberg¨ange undIO

IReader/Writer, Nichtdeterminismus, Ausnahmen

IMonadentransformer

ITeil II: Fortgeschrittene Datenstrukturen ITeil III: Nebenl¨aufigkeit

ITeil IV: The Future of Programming

3

Die Identit¨ atsmonade

IDie allereinfachste Monade:

type I d a = a

i n s t a n c e Monad I d where r e t u r n a = a

b=f = f b

4

Fehlermonaden

IErste N¨ahrung:Maybe

IMaybekennt nurNothing, daher strukturierte Fehler:

data E i t h e r a b = L e f t a | Right b type E r r o r a = E i t h e r S t r i n g a i n s t a n c e Monad ( E i t h e r S t r i n g ) where

( Right a )=f = f a ( L e f t l ) =f = L e f t l r e t u r n b = Right b

INachteil: Fester Fehlertyp IL¨osung: Typklassen

5

Die Monade Control.Monad.Error

ITypklasseErrorf¨ur Fehler c l a s s E r r o r a where

noMsg : : a

strMsg : : S t r i n g a IFehlermonade parametrisiert ¨ubere:

c l a s s (Monad m) MonadError e m where t h r o w E r r o r : : e m a

c a t c h E r r o r : : m a ( e m a ) m a

i n s t a n c e MonadError ( E i t h e r e ) where t h r o w E r r o r = L e f t

( L e f t e ) ‘ c a t c h E r r o r ‘ h a n d l e r = h a n d l e r e a ‘ c a t c h E r r o r ‘ = a

6

Die Zustandsmonade

I

IZustands¨ubergang als Funktion

newtype S t a t e s a = S t a t e {unwrap : : ( s ( a , s ) )} i n s t a n c e Monad ( S t a t e s ) where

r e t u r n a = S t a t e $ λs ( a , s )

( S t a t e g )= f = S t a t e ( u n c u r r y g . unwrap f )

INachteil 1:Zustands¨ubergangnicht-strikt(insbesonderelazy)!

IL¨osung:Strikter Zustands¨ubergang—Control.Monad.ST INachteil 2:Zustands¨ubergangFunktion

IL¨osung:Typklassen

7

Die Monad Control.Monad.State

ITypklasseStatef¨ur Zustand lesen/schreiben:

c l a s s MonadState m s where get : : m s

put : : s m ( )

IZustandsmonade parametrisiert ¨uberState:

i n s t a n c e MonadState ( S t a t e s ) s where get = S t a t e $ λs ( s , s ) put s = S t a t e $ λ ( ( ) , s )

IAber: manchmalliestman nur, manchmalschreibtman nur. . .

8

(8)

Die Lesemonade

IIntuition: Werte der Eingabeelesen und verabeiten.

ILese-Teil der Zustandsmonade

newtype Reader e a = Reader ( e a ) i n s t a n c e Monad ( Reader e ) where

r e t u r n a = Reader $ λe a ( Reader r )=f = Reader $

λe l e t Reader g = f ( r e ) i n g e

IEingabe wirdnichtmodifiziert.

IBeispiel: Lesen ausSymboltabelle(Gegenbeispiel: Datei)

9

Die Monade Control.Monad.Reader

IWie vorher: Abstraktion derLeseoperationen

INeu:LokalerZustand

c l a s s MonadReader e m where ask : : m e

l o c a l : : ( e e ) m a m a i n s t a n c e MonadReader ( Reader e ) where

ask = Reader i d

l o c a l f c = Reader $ λe runReader c ( f e ) a s k s : : ( MonadReader e m) ( e a ) m a a s k s s e l = ask = r e t u r n . s e l

10

Die Schreibmonade

IProduziert einen Strom von Werten IKein Zugriff auf geschriebene Werte m¨oglich

IBeispiel: “Logging”

newtype W r i t e r w a = W r i t e r ( a , [w ] ) i n s t a n c e Monad ( W r i t e r w) where

r e t u r n a = W r i t e r ( a , [] )

( W r i t e r ( a ,w) )=f = l e t W r i t e r ( a ’ , w’ ) = f a i n W r i t e r ( a ’ , w++ w’ ) IAbstraktion: auch ¨uberListenvon Ausgabewerten

11

Die Monade Control.Monad.Writer

ITypklasseMonoid: Verallgemeinerte Listen

c l a s s ( Monoid w, Monad m) MonadWriter w m where pass : : m ( a , w w) m a

l i s t e n : : m a m ( a , w) t e l l : : w m ( )

i n s t a n c e MonadWriter ( W r i t e r w) where pass ( W r i t e r ( ( a , f ) ,w) ) = W r i t e r ( a , f w) l i s t e n ( W r i t e r ( a ,w) ) = W r i t e r ( ( a ,w) ,w)

t e l l s = W r i t e r ( ( ) , s )

l i s t e n s : : ( MonadWriter w m) (w w) m a m ( a ,w) l i s t e n s f m = do ( a ,w)m; r e t u r n ( a , f w) c e n s o r : : ( MonadWriter w m)

(w w) m a m a

c e n s o r f m = pass $ do am; r e t u r n ( a , f )

12

Die Listenmonade

IListen sind Monaden:

i n s t a n c e Monad [] where

m=f = concatMap f m

r e t u r n x = [ x ] f a i l s = []

IIntuition:f :: a[b]Liste der m¨oglichen Resultate

IReihenfolge der M¨oglichkeiten relevant?

13

Der Monade Set

IData.Setsind Monaden:

i n s t a n c e Monad Set where

m=f = Set . u n i o n s ( Set . map f m) r e t u r n x = Set . s i n g l e t o n x

f a i l s = Set . empty

INichtvordefiniert . . .

14

Der Continuationmonade

IAuswertungskontext wird explizit modelliert.

newtype Cont r a =

Cont { runCont : : ( ( a r ) r ) }

Irist der Typ der gesamten Berechnung Ia→rist der momentane Kontext

i n s t a n c e Monad ( Cont r ) where r e t u r n a = Cont $ λk k a ( Cont c )=f = Cont $

λk c (λa runCont ( f a ) k )

Control.Monad.Cont

IcallCC: GOTO f¨ur funktionale Sprachen

c l a s s (Monad m) MonadCont m where c a l l C C : : ( ( a m b ) m a ) m a i n s t a n c e MonadCont ( Cont r ) where

c a l l C C f = Cont $

λk runCont ( f (λa Cont $ λ k a ) ) k

ILiebernichtbenutzen!

(9)

Exkurs: Was ist eigentliche eine Monade?

IMonade: Konstrukt ausKategorientheorie IMonade=(verallgemeinerter) Monoid IMonade: gegeben durchalgebraische Theorien

IOperationen endlicher (beschr¨ankter) Aritit¨at

IGleichungen

IBeispiele:Maybe,List,Set,State, . . . IMonaden in Haskell:computational monads

IStrukturierte Notation f¨urBerechnungsparadigmen

IBeispiel: Rechner mit Fehler, Nichtdeterminismus, Zustand, . . .

17

Kombination von Monaden: Das Problem

IGegeben zweiMonaden:

c l a s s Monad m1 where . . . c l a s s Monad m2 where . . .

IEs gelten weder

i n s t a n c e Monad (m1 (m2 a ) ) i n s t a n c e Monad (m2 (m1 a ) ) IProblem:Monadengesetzegelten nicht.

IL¨osung:N¨achsteVorlesung

18

Zusammenfassung

IMonaden sind praktischeAbstraktion IWir haben kennengelernt:

IFehlermonaden:Maybe,Either,MonadError

IZustandsmonaden:State,ST,IO

ILese/Schreibmonade:ReaderMonad,WriterMonad

INichtdeterminusmus:[a],Data.Set

IExplizite Spr¨unge:Continuation

IWichtigesStrukturierungsmittelf¨ur funktionale Programme IKombination bereitet (noch) Probleme . . .

19

(10)

Fortgeschrittene Techniken der Funktionalen Programmierung Vorlesung vom 10.11.09:

Monadentransformer

Christoph L¨uth, Dennis Walter Universit¨at Bremen Wintersemester 2009/10

1

Heute gibt’s:

IEine Monade istgut, mehrere Monaden sindbesser

IKombination von Monaden

IMonadentransformer

2

Fahrplan

ITeil I: Monaden und fortgeschrittene Typen

IEinf¨uhrung, Wiederholung

IZust¨ande, Zustands¨uberg¨ange undIO

IReader/Writer, Nichtdeterminismus, Ausnahmen

IMonadentransformer

ITeil II: Fortgeschrittene Datenstrukturen ITeil III: Nebenl¨aufigkeit

ITeil IV: The Future of Programming

3

Kombination von Monaden: Das Problem

IGegeben zweiMonaden:

c l a s s Monad m1 where . . . c l a s s Monad m2 where . . .

IEs gelten weder

i n s t a n c e Monad (m1 (m2 a ) ) i n s t a n c e Monad (m2 (m1 a ) )

IProblem:Monadengesetzegelten nicht.

4

Monadentransformer

IMonadentransformer:

IErweiterbare Monade

IMonade mitLoch newtypeM a = . . . i n s t a n c e Monad M where

f =g = . . . r e t u r n x = . . .

newtype M m a = . . .

i n s t a n c e Monad m⇒ Monad M m where f =g = . . .

r e t u r n x = . . .

5

Monadentransformer: Beispiele

1.Beispiel:Zustandsmonadentransformer type S t a t e T s m a = s m ( s , a )

I Zustandsbasierte Berechnungenin einer anderen Monadem

I StateT s Identity ist Zustandsmonade

2.Beispiel:Fehlermonadentransformer

type E r r o r T e m a = m ( E i t h e r e a )

I Fehlerbehaftete Berechnungenin einer anderen Monadem

I ErrorT e Identity ist Fehlermonade

6

Reihenfolge beachten!

IKombination vonStateundError IErstZustand, dannFehler:

type E r r o r S t a t e s a =

E r r o r T ( S t a t e T s I d ) = E i t h e r S t r i n g ( s ( s , a ) )

IBerechungm :: ErrorState s a: Fehler oder zustandsbehaftet

IE.g. Fehler in Haskell

IErstFehler, dannZustand:

type S t a t e E r r o r s a = s ( s , E i t h e r S t r i n g a )

IBerechungm :: StateError s a: Immer zustandsbehaftet, Resultat Fehler oder normal

IE.g. Fehler in imperativen Sprachen

Standardtransformer

Standard-Monade Transformer Standard-Typ Transformierter Typ

Error ErrorT Either e a m (Either e a)

State StateT s (a, s) s m (a,s)

Reader ReaderT r a rm a

Writer WriterT (a,w) m (a,w)

Cont ContT (ar)r (am r)m r

Quelle:http://www.haskell.org/all˙about˙monads/

(11)

Fallbeispiel: ein Modularer Interpreter

IZiel: Interpreter f¨ur eine einfache imperative Sprache IModularer Aufbau:

1.Nur Zustand

2.Ausgabe

3.Eingabe

4.Fehler und Fehlerbehandlung

9

Zusammenfassung

IWarumMonaden kombinieren?

I Typ definiertEffekt

I E.g.WriterT— nur Logging, kein Zustand

I Pragmatisch: dieIO-Monade (imperativ)

IVorteileMonadentransfomer:

I Erlauben modulare Kombination von Monaden

I Standard-B¨ucherei (Monad Template Library) bietet Standard-Monaden als praktischen Bausatz

INachteileMonadentransformer:

I F¨ur neue TransformerKombinationmitallenanderen zu bedenken!

I Nichtkompositional

IN¨achste Woche:?

10

(12)

Fortgeschrittene Techniken der Funktionalen Programmierung Vorlesung vom 17.11.09:

Der Zipper

Christoph L¨uth, Dennis Walter Universit¨at Bremen Wintersemester 2009/10

1

Fahrplan

ITeil I: Monaden und fortgeschrittene Typen

ITeil II: Fortgeschrittene Datenstrukturen

I Der Zipper

I Str¨ome, Graphen, unendliche Datenstrukturen

ITeil III: Nebenl¨aufigkeit

ITeil IV: The Future of Programming

2

Das Problem

IFunktional = kein Zustand

IWiedestruktiver Update?

IManipulationinnerhalbeiner Datenstruktur

IBeispiel: ZeilenorientierterEditor, Abstrakte Syntax

IL¨osung: DerZipper

IKeine feste Datenstruktur, sondern einSchema

3

Ein einfacher Editor

IDatenstrukturen:

type Text = [ S t r i n g ]

data Pos = Pos { l i n e : : Int , c o l : : I n t} data E d i t o r = Ed { t e x t : : Text

, c u r s o r : : Pos }

IOperationen: Cursorbewegen(links) g o l e f t : : E d i t o r E d i t o r g o l e f t Ed{t e x t= t , c u r s o r= c}

| c o l c 0 = e r r o r ”At s t a r t o f l i n e ”

| o t h e r w i s e =

Ed{t e x t= t , c u r s o r=c{c o l= c o l c− 1}}

4

Beispieloperationen

ITextrechtseinf¨ugen:

i n s e r t r i g h t : : E d i t o r S t r i n g E d i t o r i n s e r t r i g h t Ed{t e x t= t , c u r s o r= c} t e x t =

l e t ( as , bs ) = s p l i t A t ( c o l c ) ( t ! ! l i n e c ) i n Ed{t e x t= updateAt ( l i n e c ) t

( as ++ t e x t++ bs ) , c u r s o r= c}

updateAt : : I n t [ a ] a [ a ] updateAt n as a = c a s e s p l i t A t n as o f

( bs , [] ) e r r o r ” updateAt : l i s t too s h o r t . ” ( bs , : cs ) bs ++ a : cs

IProblem:Aufwandf¨ur Manipulation

5

Manipulation strukturierter Datentypen

IAnderes Beispiel:n-¨are B¨aume(rose trees) data Tree a = Leaf a

| Node [ Tree a ] d e r i v i n g Show

I Bsp: Abstrakte Syntax von einfachen Ausdr¨ucken

IUpdateauf Beispieltermt=a∗b−c∗d: ersetzebdurchx+y t = Node [ Leaf ”−”

, Node [ Leaf ”∗” , Leaf ”a” , Leaf ”b” ] , Node [ Leaf ”∗” , Leaf ” c ” , Leaf ”d” ] ]

6

Der Zipper

IIdee:Kontextnichtwegwerfen!

INicht:typePath = [Int]

ISondern:

data Ctxt a = Empty

| Cons [ Tree a ] ( Ctxt a ) [ Tree a ]

IKontext ist ‘inverse Umgebung’ (“Like a glove turned inside out”)

ILoc aistBaummitFokus

newtype Loc a = Loc ( Tree a , Ctxt a )

IWarumnewtype?

Zipping Trees: Navigation

IFokus nachlinks

g o l e f t : : Loc a Loc a g o l e f t ( Loc ( t , c ) ) = c a s e c o f

Empty e r r o r ” g o l e f t at empty ”

Cons ( l : l e ) up r i Loc ( l , Cons l e up ( t : r i ) ) Cons [] e r r o r ” g o l e f t o f f i r s t ” IFokus nachrechts

g o r i g h t : : Loc a Loc a g o r i g h t ( Loc ( t , c ) ) = c a s e c o f

Empty e r r o r ” g o r i g h t at empty ”

Cons l e up ( r : r i ) Loc ( r , Cons ( t : l e ) up r i ) Cons [] e r r o r ” g o r i g h t o f l a s t ”

(13)

Zipping Trees: Navigation

IFokus nachoben

go up : : Loc a Loc a

go up ( Loc ( t , c ) ) = c a s e c o f Empty e r r o r ” go up o f empty ” Cons l e up r i

Loc ( Node ( r e v e r s e l e ++ t : r i ) , up ) IFokus nachunten

go down : : Loc a Loc a

go down ( Loc ( t , c ) ) = c a s e t o f Leaf e r r o r ” go down at l e a f ” Node [] e r r o r ” go down at empty ” Node ( t : t s ) Loc ( t , Cons [] c t s )

9

Zipping Trees: Navigation

IHilfsfunktion:

top : : Tree a→ Loc a top t = ( Loc ( t , Empty ) )

IDamit andere Navigationsfunktionen:

path : : Loc a [ I n t ] Loc a path l [] = l

path l ( i : ps )

| i 0 = path ( go down l ) ps

| i > 0 = path ( g o l e f t l ) ( i1) ps

10

Einf¨ ugen

IEinf¨ugen: Wo?

ILinksdes Fokus einf¨ugen

i n s e r t l e f t : : Tree a Loc a Loc a i n s e r t l e f t t1 ( Loc ( t , c ) ) = c a s e c o f

Empty e r r o r ” i n s e r t l e f t : i n s e r t at empty ” Cons l e up r i Loc ( t , Cons ( t1 : l e ) up r i ) IRechtsdes Fokus einf¨ugen

i n s e r t r i g h t : : Tree a Loc a Loc a i n s e r t r i g h t t1 ( Loc ( t , c ) ) = c a s e c o f

Empty e r r o r ” i n s e r t r i g h t : i n s e r t at empty ” Cons l e up r i Loc ( t , Cons l e up ( t1 : r i ) ) IUnterhalbdes Fokus einf¨ugen

i n s e r t d o w n : : Tree a Loc a Loc a i n s e r t d o w n t1 ( Loc ( t , c ) ) = c a s e t o f

Leaf e r r o r ” i n s e r t d o w n : i n s e r t at l e a f ” Node t s Loc ( t1 , Cons [] c t s )

11

Ersetzen und L¨ oschen

IUnterbaum im Fokusersetzen:

update : : Tree a Loc a Loc a update t ( Loc ( , c ) ) = Loc ( t , c ) IUnterbaum im Fokus l¨oschen: wo ist der neue Fokus?

1. RechterBaum, wenn vorhanden 2. LinkerBaum, wenn vorhanden 3. Elternknoten

d e l e t e : : Loc a Loc a d e l e t e ( Loc ( , p ) ) = c a s e p o f

Empty Loc ( Node [] , Empty )

Cons l e up ( r : r i ) Loc ( r , Cons l e up r i ) Cons ( l : l e ) up [] Loc ( l , Cons l e up [] ) Cons [] up [] Loc ( Node [] , up )

I “We note thatdeleteis not such a simple operation.”

12

Schnelligkeit

IWieschnellsind Operationen?

IAufwand: go leftO(left(n)), alle anderenO(1).

IWarumsind Operationen so schnell?

IKontext bleibterhalten

IManipulation: reineZeiger-Manipulation

13

Der Zipper als Monade

ILocMist Zustandsmonade mit ZustandLoc

newtype LocM a b = LocM {l o c S t : : S t a t e ( Loc a ) b}

d e r i v i n g ( Functor , Monad , MonadState ( Loc a ) ) IStartfunktion

run : : LocM a b Tree a ( b , Loc a ) run l t = r u n S t a t e ( l o c S t l ) ( top t ) IZugriff auf Baum imFokus

c u r r e n t : : LocM a ( Tree a )

c u r r e n t = do Loc ( l , c ) get ; r e t u r n l INavigation

l e f t : : LocM a ( ) l e f t = modify g o l e f t

−−etc.

14

Zipper Monad: Manipulation

IL¨oschen:

d e l : : LocM a ( ) d e l = modify d e l e t e IUpdate:

upd : : Tree a LocM a ( ) upd t = modify ( update t ) IEinf¨ugen (bsp rechts):

i n s r : : Tree a LocM a ( ) i n s r t = modify ( i n s e r t r i g h t t ) IHilfspr¨adikat:rightm¨oglich?

h a s r i g h t : : Loc a Bool h a s r i g h t ( Loc ( l , c ) ) = c a s e c o f

( Cons ( : ) ) True ; F a l s e h a s r i : : LocM a Bool

h a s r i = g e t s h a s r i g h t 15

Zipper f¨ ur andere Datenstrukturen

IBin¨are B¨aume:

data Tree a = Leaf a | Node ( Tree a ) ( Tree a )

IKontext:

data Ctxt a = Empty

| Le ( Ctxt a ) ( Tree a )

| Ri ( Tree a ) ( Ctxt a ) newtype Loc a = Loc ( Tree a , Ctxt a )

16

(14)

Tree-Zipper: Navigation

IFokus nachlinks

g o l e f t : : Loc a Loc a

g o l e f t ( Loc ( t , c t x ) ) = c a s e c t x o f Empty e r r o r ” g o l e f t at empty ” Le c r e r r o r ” g o l e f t o f l e f t ” Ri l c Loc ( l , Le c t )

IFokus nachrechts

g o r i g h t : : Loc a Loc a

g o r i g h t ( Loc ( t , c t x ) ) = c a s e c t x o f Empty e r r o r ” g o r i g h t at empty ” Le c r Loc ( r , Ri t c )

Ri e r r o r ” g o r i g h t o f r i g h t ”

17

Tree-Zipper: Navigation

IFokus nachoben

go up : : Loc a Loc a

go up ( Loc ( t , c t x ) ) = c a s e c t x o f Empty e r r o r ” go up o f empty ” Le c r Loc ( Node t r , c ) Ri l c Loc ( Node l t , c ) IFokus nachunten links

g o d o w n l e f t : : Loc a Loc a g o d o w n l e f t ( Loc ( t , c ) ) = c a s e t o f

Leaf e r r o r ” go down at l e a f ” Node l r Loc ( l , Le c r )

IFokus nachunten rechts

g o d o w n r i g h t : : Loc a Loc a g o d o w n r i g h t ( Loc ( t , c ) ) = c a s e t o f

Leaf e r r o r ” go down at l e a f ” Node l r Loc ( r , Ri l c )

18

Tree-Zipper: Einf¨ ugen und L¨ oschen

IEinf¨ugenlinks

i n s l e f t : : Tree a Loc a Loc a

i n s l e f t t1 ( Loc ( t , c t x ) ) = Loc ( t , Ri t1 c t x ) IEinf¨ugenrechts

i n s r i g h t : : Tree a Loc a Loc a

i n s r i g h t t1 ( Loc ( t , c t x ) ) = Loc ( t , Le c t x t1 ) IL¨oschen

d e l e t e : : Loc a Loc a d e l e t e ( Loc ( , c ) ) = c a s e c o f

Empty e r r o r ” d e l e t e o f empty ” Le c r Loc ( r , c )

Ri l c Loc ( l , c )

INeuer Fokus: anderer Teilbaum

19

Tree-Zipper: Variation

IBin¨are B¨aume, Werte imKnoten:

data Tree a = N i l | Node ( Tree a ) a ( Tree a )

IKontext enth¨altKnotenwert data Ctxt a = Empty

| Le ( Ctxt a ) a ( Tree a )

| Ri ( Tree a ) a ( Ctxt a )

IFunktionen ¨ahnlich, aber:

I deletetotal, l¨oschtKnoteninhaltim Kontext

20

Zipping Lists

IListen:

data L i s t a = N i l | Cons a ( L i s t a )

IDamit:

data Ctxt a = Empty | Snoc ( Ctxt a ) a

IListen sind ihr ‘eigener Kontext’ : List a=Ctxt a

21

Zipping Lists: Fast Reverse

IListenumkehrschnell:

f a s t r e v : : [ a ] [ a ] f a s t r e v xs = r e v xs []

r e v : : [ a ] [ a ] [ a ] r e v [] as = as

r e v ( x : xs ) as = r e v xs ( x : as )

IZweites Argument vonrev:Kontext

I Liste der Elemente davor inumgekehrterReihenfolge

22

Zusammenfassung

IDerZipper

IManipulation von Datenstrukturen

IZipper = Kontext + Fokus

IEffiziente destruktive Manipulation INachteile

INicht richtig generisch —Schema, keine B¨ucherei

IViel schematischer Code f¨ur jeden Datentyp

IAbhilfe:Generic Zipper

IN¨achstes Mal: Graphen, Str¨ome, unendliche Datenstrukturen

(15)

Fortgeschrittene Techniken der Funktionalen Programmierung Vorlesung vom 24.11.09:

Unendliche Datentypen und Graphen

Christoph L¨uth, Dennis Walter Universit¨at Bremen Wintersemester 2009/10

1

Fahrplan

ITeil I: Monaden und fortgeschrittene Typen

ITeil II: Fortgeschrittene Datenstrukturen

I Der Zipper

I Str¨ome, Graphen, unendliche Datenstrukturen

ITeil III: Nebenl¨aufigkeit

ITeil IV: The Future of Programming

2

Das Tagesmen¨ u

IReprise:Str¨ome(uendliche Listen)

IDoppeltverketteteListen

IGraphen

3

Unendliche Datenstrukturen: Str¨ ome

IStr¨ome: Unendliche Listen

data Stream a = Stream { hd : : a , t l : : Stream a }

IObservatoren:

hd : : Stream a a t l : : Stream a Stream a

4

Bsp: Fibonacci-Zahlen

IFibonacci-Zahlen alsStrom

ISeifibs :: [Integer]Strom aller Fib’zahlen:

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 IDamit ergibt sich:

f i b s : : Stream I n t e g e r

f i b s = Stream 1 ( Stream 1 $ z i pS (+) f i b s ( t l f i b s ) ) In-te Fibonaccizahl mitith n fibs

IAufwand:linear, dafibsnur einmal ausgewertet wird.

5

Doppelt Verkettete Listen

IIn Haskell wie in Java/C: Zeiger aufVorg¨anger,Nachfolger data DList a = DLNode { prev : : DList a

, v a l : : a

, next : : DList a }

| DLEmpty

I deriving(Eq, Show)???

IKeinfreierDatentyp: es geltenInvarianten d /= DLEmpty && next d /= DLEmpty

prev ( next d)= d d /= DLEmpty && prev d /= DLEmpty

next ( prev d)= d

6

Listen erzeugen

IDoppelt verkettete Listen erzeugen:

f r o m L i s t : : [ a ] DList a f r o m L i s t as = mkDList DLEmpty as mkDList : : DList a [ a ] DList a mkDList c u r r p r e v [] = DLEmpty mkDList c u r r p r e v ( x : xs ) =

l e t he r e = DLNode c u r r p r e v x ( mkDList h er e xs ) i n he r e

IProblem: Knoten einf¨ugen/l¨oschen

IEinfachefalscheL¨osung

IRichtige L¨osung istO(n)

7

Zusammenfassung

IVorteile:

I Vorg¨anger/NachfolgerO(1)

INachteile:

I Einf¨ugen/L¨oschenO(n)

8

(16)

Graphen als unendliche Datentypen

IEin Graph ist eine Liste von Knoten

data Node a b = Node a [ Vertex a b ] data Vertex a b = Vertex b ( Node a b ) type Graph a b = [ Node a b ]

IDamit Beispielgraph:

g : : Graph S t r i n g S t r i n g

g = l e t n1 = Node ”a” [ Vertex ”R” n2 ]

n2 = Node ”b” [ Vertex ”L” n1 , Vertex ”D” n3 ] n3 = Node ” c ” [ Vertex ”U” n1 ]

i n g

IProblem:Einf¨ugen/L¨oschen (King & Launchbury, 1995)

9

Graphen als induktive Datenstrukturen

IMartin Erwig (2001)— Functional Graph Library (FGL)

IIdeen:

1. Knoten habenexplizite Identit¨at 2. Graph istinduktivdefiniert IEin Graph ist

I entwederleer

I oderErweiterungeines Graphen (Kontext) type Node = I n t

type Adj b = [ ( b , Node ) ]

type Ctx a b = ( Adj b , Node , a , Adj b ) data Gr a b = Empty | Ctx a b :& Gr a b

10

Pattern Matching

IGraphkeinfreierDatentyp — Beispiel IDatentypGraphmussabstraktsein

IFallunterscheidung auf Konstruktoren vonGraphnicht m¨oglich IF¨alle:

ILeererGraph

isEmpty : : Gr a b Bool

INicht-leerer Graph:KontextplusRest

matchAny : : Gr a b ( Ctx a b , Gr a b )

11

Einfache Funktionen

IMatch auf einen bestimmten Knoten:

match : : Node Gr a b ( Maybe ( Ctx a b ) , Gr a b ) Invariante:

matchv g= (Just(is,w,l,os),h) =⇒v=w IMap:

gmap : : ( Ctx a b Ctx c d ) Gr a b Gr c d gmap f g | isEmpty g = Empty

| o t h e r w i s e = f c :& (gmap f g ’ ) where ( c , g ’ ) = matchAny g

IDamit Umkehr aller Kanten:

swap : : Ctx a b Ctx a b swap ( p , v , l , s ) = ( s , v , l , p ) g re v : : Gr a b Gr a b

g re v = gmap swap

12

Beweise von Eigenschaften

IDatentypGr a bist nichtfrei, aberinduktiv IInduktion als zul¨assigesBeweisprinzip:

emptyg−→P g ∀c g.P g−→P(c: &g)

∀g.P g

IDamitzeigen:

gmapf.gmapf0 = gmap(f.f0) (gmap fusion)

grev.grev = id (grev inv)

13

Tiefensuche

IAufspannenden BauminTiefensuche data Tree a = Tree a [ Tree a ]

df : : [ Node ] Gr a b ( [ Tree Node ] , Gr a b ) df [] g = ( [] , g )

df ( v : vs ) g = c a s e match v g o f

( J u s t c , h ) ( Tree v t1 : t2 , g2 ) where ( t1 , g1)= df ( suc c ) h

( t2 , g2)= df vs g1 ( Nothing , h ) df vs h

d f f : : [ Node ] Gr a b [ Tree Node ] d f f vs g = f s t ( df vs g )

IAnwendung:SCC (stark verbundene Komponenten)

14

Breitensuche

IAufspannenden BauminBreitensuche

IProblem: Baum w¨achst nach ‘unten’ — daher Pfade type Path = [ Node ]

type RTree = [ Path ]

b f t : : Node Gr a b RTree b f t v = bf [ [ v ] ]

bf : : [ Path ] Gr a b RTree bf [] g = []

bf (p@( v : ) : ps ) g = c a s e match v g o f

( J u s t c , h ) p : bf ( ps ++ map ( : p ) ( suc c ) ) h ( Nothing , h ) bf ps h

IVerbesserung:Queue Pathstatt[Path]benutzen IAnwendung:k¨urzester Pfad

FGL als B¨ ucherei

IViele weitere Algorithmen

IGraphen alsKlasse, verschiedene Implementationen

IHackage:Data.Graph.Inductive

IMehr hier:

http://web.engr.oregonstate.edu/˜erwig/fgl/haskell/

(17)

Zusammenfassung

IUnendliche Datenstrukturenrealisiert durch Referenzen

IProgrammierung: Observatoren/Destruktoren vs. Konstruktoren

IBeispiel: doppelt verkettete Listen IGraphen in Haskell

IBeispiel f¨urinduktive, aber nichtfreieDatenstruktur

IKompakte Darstellung, effiziente Algorithmen m¨oglich

IN¨achste Woche: Nebenl¨aufigkeit

17

(18)

Fortgeschrittene Techniken der Funktionalen Programmierung Vorlesung vom 01.12.09:

Grundlagen der Nebenl¨aufigkeit in Haskell

Christoph L¨uth, Dennis Walter Universit¨at Bremen Wintersemester 2009/10

1

Fahrplan

ITeil I: Monaden und fortgeschrittene Typen ITeil II: Fortgeschrittene Datenstrukturen ITeil III: Nebenl¨aufigkeit

I Grundlagen

I Abstraktionen und Ausnahmebehandlung

I Software Transactional Memory ITeil IV: The Future of Programming

2

Heute gibt’s hier

Nebenl¨aufigkeit

IGrundkonzepte

IImplementation in Haskell

IBasiskonzepte

3

Konzepte der Nebenl¨ aufigkeit

I Thread (lightweight process) vs. Prozess Programmiersprache/Betriebssystem Betriebssystem (z.B. Java, Haskell, Linux)

gemeinsamerSpeicher getrennterSpeicher

Erzeugungbillig Erzeugungteuer

mehrereproProgramm einerproProgramm

IMultitasking:

I pr¨aemptiv:Kontextwechsel wirderzwungen

I kooperativ:Kontextwechsel nurfreiwillig

4

Zur Erinnerung: Threads in Java

IErweiterung der KlassenThreadoderRunnable IGestartet wird Methoderun()— durch eigene ¨uberladen IStarten des Threads durch Aufruf der Methodestart() IKontextwechsel mityield()

IJe nach JVM kooperativoderpr¨aemptiv.

ISynchronisation mitsynchronize

5

Threads in Haskell: Concurrent Haskell

ISequentiellesHaskell: Reduktion eines Ausdrucks

I Compiler legt Reihenfolge fes (outermost leftmost — verz¨ogerte Auswertung)

INebenl¨aufigesHaskell: Reduktion eines Ausdrucks anmehreren Stellen Ighcundhugsimplementieren Haskell-Threads

Ighc:pr¨aemptiv,hugs:kooperativ

IModulControl.Concurrententh¨alt Basisfunktionen IWenige Basisprimitive, darauf aufbauend Abstraktionen

6

Wesentliche Typen und Funktionen

IJeder Thread hat einen Identifier: abstrakter TypThreadId INeuen Thread erzeugen:forkIO:: IO()-¿ IO ThreadId IThread stoppen:killThread :: ThreadId -¿ IO () IKontextwechsel:yield :: IO ()

IEigener Thread:myThreadId :: IO ThreadId IWarten:threadDelay :: Int -¿ IO ()

Rahmenbedingungen

IZeitscheiben:

I Tick: Default 20ms

I Contextswitchpro Tick bei Heapallokation

I ¨Anderungen perKommandozeilenoptionen:+RTS -V¡time¿ -C¡time¿

IBlockierung:

I Systemaufrufe blockierenalle Threads

I Mit threaded library (-threaded) nicht alle

I Aber: Haskell Standard-IO blockiertnur den aufrufenden Thread

(19)

Concurrent Haskell — erste Schritte

IEin einfaches Beispiel:

w r i t e : : Char IO ( )

w r i t e c = putChar c w r i t e c main : : IO ( )

main = f o r k I O ( w r i t e ’X ’ ) w r i t e ’O’

IAusgabeghc: (X|O) IAusgabehugs: (X|O)

9

Synchronisation mit MVars

IBasissynchronisationmechanismusin Concurrent Haskell

I Alles andereabgeleitet

IMVar aver¨anderbareVariable (vgl.IORef a) IEntwederleerodergef¨ulltmit Wert vom Typa IVerhalten beim Lesen und Schreiben

Zustand vorher: leer gef¨ullt

Lesen blockiert(bis gef¨ullt) danach leer Schreiben danach gef¨ullt blockiert(bis leer)

I NB.Aufweckenblockierter ProzesseeinzelninFIFO

10

Basisfunktionen MVars

INeue Variable erzeugen (leer oder gef¨ullt):

newEmptyMVar : : IO (MVar a ) newMVar : : a IO (MVar a )

ILesen:

takeMVar : : MVar a IO a

ISchreiben:

putMVar : : MVar a a IO ( )

11

Abgeleitete Funktionen MVars

INicht-blockierendes Lesen/Schreiben:

tryTakeMVar : : MVar a IO ( Maybe a ) tryPutMVar : : MVar a a IO Bool

I ¨Anderung der MVar:

swapMVar : : MVar a a IO a

withMVar : : MVar a ( a IO b ) IO b modifyMVar : : MVar a ( a IO ( a , b ) ) IO b

I Achtung:race conditions

12

Ein einfaches Beispiel ohne Synchronisation

INebenl¨aufige Eingabe von der Tastatur

import C o n t r o l . Monad( f o r e v e r , r e p l i c a t e M ) import C o n t r o l . Concurrent

echo : : S t r i n g IO ( ) echo p = f o r e v e r $ do

putStrLn ( ”∗∗∗ P l e a s e e n t e r l i n e f o r ”++p ) l i n e g e t L i n e

nrandomRIO (1 ,100)

r e p l i c a t e M n $ p u t S t r ( p++ ” : ”++ l i n e++” ” ) main : : IO ( )

main = f o r k I O ( echo ”2” ) echo ”1”

IProblem: gleichzeitige Eingabe IL¨osung:MVarsynchronisiert Eingabe

13

Ein einfaches Beispiel mit Synchronisation

IMVarvollEingabe m¨oglich

I Also: initial voll

IInhalt der MVar irrelevant:MVar () echo : : MVar ( ) S t r i n g IO ( ) echo f l a g p = f o r e v e r $ do

takeMVar f l a g

putStrLn ( ”∗∗∗ P l e a s e e n t e r l i n e ”++ p ) l i n e g e t L i n e

nrandomRIO (1 ,100)

r e p l i c a t e M n $ p u t S t r ( p++ ” : ”++ l i n e++” ” ) putMVar f l a g ( )

main : : IO ( )

main = do f l a g newMVar ( )

f o r k I O ( echo f l a g ”3” ) f o r k I O ( echo f l a g ”2” ) echo f l a g ”1”

14

Das Standardbeispiel

ISpeisende Philosopen

IPhilosophi:

Ivor dem Esseni-tes und(i+1)modn-tes St¨abchen nehmen

Inach dem Essen wieder zur¨ucklegen

ISt¨abchen modelliert alsMVar ()

15

Speisende Philosophen

p h i l o : : [ MVar ( ) ] I n t IO ( ) p h i l o c h o p s t i c k s i = f o r e v e r $ do

l e t num phil = l e n g t h ( c h o p s t i c k s )

−−Thinking:

putStrLn ( ” P h i l #”++ show i ++” t h i n k s . . . ” ) randomRIO (10 , 200)=t h r e a d D e l a y

−−Get ready to eat:

takeMVar ( c h o p s t i c k s ! ! i )

takeMVar ( c h o p s t i c k s ! ! ( ( i +1) ‘mod ‘ num phil ) )

−−Eat:

putStrLn ( ” P h i l #”++ show i ++” e a t s . . . ” ) randomRIO (10 , 200)=t h r e a d D e l a y

−−Done eating:

putMVar ( c h o p s t i c k s ! ! i ) ( )

putMVar ( c h o p s t i c k s ! ! ( ( i +1) ‘mod ‘ num phil ) ) ( )

16

(20)

Speisende Philosophen

IHauptfunktion:nSt¨abchen erzeugen IAnzahl Philosophen in der Kommandozeile

main = do a : getArgs l e t num= read a

c h o p s t i c k s r e p l i c a t e M num $ newMVar ( ) mapM ( f o r k I O . ( p h i l o c h o p s t i c k s ) ) [ 0 . . num1]

b l o c k

IHilfsfunktionblock: blockiert aufrufenden Thread b l o c k : : IO ( )

b l o c k = newEmptyMVar=takeMVar INB: Hauptthread terminiert — Programm terminiert!

17

Abstraktion: Semaphoren

IAbstrakter DatentypQSem

IBetretenkritischer Abschnitt(P):waitQSem :: QSemIO () IVerlassenkritischer Abschnitt(V):signalQSem :: QSemIO () ISemaphore: Z¨ahler plus evtl. wartende Threads

I Perniedrigt Z¨ahler, blockiert ggf. aufrufenden Thread

I Verh¨oht Z¨ahler, gibt ggf. blockierte Threads frei

IImplementierung von Semaphoren mitMVar: eigenes Scheduling IVariation:Quantitative Semaphoren

I Z¨ahler kann um Parameternerh¨oht/erniedrigt werden

18

Semaphoren: die P-Operation

data QSem = QSem (MVar ( Int , [ MVar ( ) ] ) ) IMVar ..f¨ur die ganze Semaphore, darin:

IZ¨ahler der Prozesse im kritischen Abschnitt

IListe von wartenden Prozessen (MVar ()) newQSem : : I n t IO QSem

newQSem n = do mnewMVar ( n , [] ) r e t u r n (QSem m)

19

Semaphoren: die P-Operation

IEintrittin kritischen Abschnitt

IWenn Eintritt m¨oglich, Z¨ahler erniedrigen IAnsonsten blockieren (Reihenfolge!) waitQSem : : QSem IO ( ) waitQSem (QSem sem ) = do

( a v a i l , b l o c k e d ) takeMVar sem i f a v a i l > 0 then

putMVar sem ( a v a i l1, [] ) e l s e do

b l o c k newEmptyMVar

putMVar sem (0 , b l o c k e d++ [ b l o c k ] ) takeMVar b l o c k

20

Semaphoren: die V-Operation

IVerlassendes kritischen Abschnitts IFalls wartende threads, einen aufwecken.

IAlternatives Scheduling:

Iam Anfang hinzuf¨ugen, vom Anfang nehmen (einfacher,unfair)

Iam besten:zuf¨alligeAuswahl signalQSem : : QSem IO ( ) signalQSem (QSem sem ) = do

( a v a i l , b l o c k e d ) takeMVar sem c a s e b l o c k e d o f

[] putMVar sem ( a v a i l +1, [] ) b l o c k : blocked ’ do

putMVar sem (0 , blocked ’ ) putMVar b l o c k ( )

21

Zusammenfassung

IConcurrent Haskellbietet

I Threadsauf Quellsprachenebene

I Synchronisierung mitMVars

I Durchschlankes Designeinfache Implementierung IFunktionales Paradigma erlaubtAbstraktionen

I Beispiel:Semaphoren

IN¨achste Woche:Kan¨aleundAusnahmen.

22

(21)

Fortgeschrittene Techniken der Funktionalen Programmierung Vorlesung vom 08.12.09:

Nebenl¨aufigkeit in Haskell: Abstraktionen und Ausnahmen

Christoph L¨uth, Dennis Walter Universit¨at Bremen Wintersemester 2009/10

1

Fahrplan

ITeil I: Monaden und fortgeschrittene Typen ITeil II: Fortgeschrittene Datenstrukturen ITeil III: Nebenl¨aufigkeit

I Grundlagen

I Abstraktionen und Ausnahmebehandlung

I Software Transactional Memory

ITeil IV: The Future of Programming

2

Tagesmen¨ u

IAbstraktionen:Kan¨ale IFallbeispiel:

ITalk

IAusnahmebehandlung:

IErweiterbare Ausnahmen

IUnscharfe Ausnahmen

IAsynchrone Ausnahmen

3

Kan¨ ale

ITypsicheres Lesen/Schreiben inFIFO-Ordnung

IBlockiertwenn leer data Chan a . . .

newChan : : IO ( Chan a )

writeChan : : Chan a a IO ( ) readChan : : Chan a IO a

I Bonus:Duplizierbar (“Broadcast”)

4

Kan¨ ale

IEin Kanal besteht aus Strom mit einem Lese- und Schreibende:

data Chan a = Chan (MVar ( Stream a ) ) (MVar ( Stream a ) )

IHierMVar, um Lesen/Schreiben zu synchronisieren IEin Strom istMVar (ChItem a):

Ientweder leer,

Ioder enth¨alt Werte aus Kopfaund Rest.

type Stream a = MVar ( ChItem a ) data ChItem a = ChItem a ( Stream a )

5

In einen Kanal schreiben

INeues Ende (hole) anlegen IWert in altes Ende schreiben

IZeiger auf neues Ende setzen

writeChan : : Chan a a IO ( ) writeChan ( Chan w r i t e ) v a l = do

new hole newEmptyMVar o l d h o l e takeMVar w r i t e

putMVar o l d h o l e ( ChItem v a l new hole ) putMVar w r i t e new hole

IKann nicht blockieren —writeimmer gef¨ullt.

IOriginal-Code benutztmodifyMVar— Ausnahmesicher!

6

Aus Kanal lesen

IAnfang auslesen, Anfangszeiger weitersetzen IKann blockieren(*)wenn Kanal leer

readChan : : Chan a IO a readChan ( Chan read ) = do

r e a d e n d takeMVar read

( ChItem v a l new read end ) readMVar r e a d e n d −−* putMVar read new read end

r e t u r n v a l

IreadMVar :: MVar a→IO aliestMVar, schreibt Wert zur¨uck.

IreadMVarstatttakeMVar, um Duplikation zu erm¨oglichen

7

Neuen Kanal erzeugen

ILese-Ende = Schreib-Ende newChan : : IO ( Chan a ) newChan = do

h o l e newEmptyMVar read newMVar h o l e w r i t e newMVar h o l e r e t u r n ( Chan read w r i t e )

8

(22)

Weitere Kanalfunktionen

IZeichen wieder vorne einh¨angen:

unGetChan : : Chan a a IO ( )

IKanal duplizieren (Broadcast):

dupChan : : Chan a IO ( Chan a )

IKanalinhalt als (unendliche) Liste:

getChanContents : : Chan a IO [ a ]

IAuswertung terminiert nicht, sondern blockiert

9

Fallbeispiel: Talk

IZiel: ein Programm, um sich ¨uber das Internetz zu unterhalten (talk, IRC, etc.)

IVerteilte Architektur:

Client Client Client

Client Server

IHier: Implementierung des Servers

I Netzverbindungen durchSocket

10

Socketprogrammierung

ISocket erzeugen, an Namen binden, mitlisten Verbindungsbereitschaft anzeigen

IZustandsbasierte Verbindung:

IServerseite: mitacceptauf eingehende Verbindungen warten

IJede Verbindung erzeugt neuen Filedescriptor

inh¨arent nebenl¨aufiges Problem!

IClientseite: MitconnectVerbindung aufnehmen.

IZustandslose Verbindung:sendTozum Senden,recvFromzum Empfangen.

IGHC-ModulNetwork

ILow-level Funktionen inNetwork.Socket

11

Das Modul Network

ISockets:

type Socket

data PortID = S e r v i c e S t r i n g −−z.B. ”ftp”

| PortNumber PortNumber

| UnixSocket S t r i n g −−Socket mit Namen type Hostname = S t r i n g

i n s t a n c e Num PortNumber IZustandsbasiert:

l i s t e n O n : : PortID IO Socket

accept : : Socket IO ( Handle , Hostname , PortNumber ) connectTo : : Hostname PortID IO Handle

IZustandslos:

sendTo : : HostName PortID S t r i n g IO ( ) recvFrom : : HostName PortID IO S t r i n g

12

Serverarchitektur

IEin Kanal zur Nachrichtenverbreitung:

Ieine Nachricht, viele Empf¨anger (broadcast)

IRealisierung mittelsdupChan IZentraler Scheduler

IF¨ur jede ankommende Verbindung neuer Thread:

INachrichten vom Socket auf den Kanal schreiben

INachrichten vom Kanal in den Socket schreiben

IProblem: Wie aus SocketoderKanal lesen wenn beide blockieren?

IL¨osung: Zwei Threads IClient:telnet

13

Talk 0.1: Hauptprogramm

main =do a : getArgs

l e t p = f r o m I n t e g e r ( read a ) s l i s t e n O n ( PortNumber p ) chnewChan

loop s ch

14

Talk 0.1: Hauptschleife

loop s ch = f o r e v e r $ do ( handle , wh , p ) accept s h S e t B u f f e r i n g handle No B uffering

putStrLn $ ”New c o n n e c t i o n from ”++ wh++

” on p o r t ”++ show p

ch2 dupChan ch

f o r k I O ( newUser handle ch2 )

Talk 0.1: Benutzerprozess

newUser : : Handle Chan S t r i n g IO ( ) newUser s o c k e t msgch =

f o r k I O ( f o r e v e r read ) f o r e v e r w r i t e where read : : IO ( )

read = hGetLine s o c k e t =writeChan msgch w r i t e : : IO ( )

w r i t e = readChan msgch=hPutStrLn s o c k e t

Referenzen

ÄHNLICHE DOKUMENTE

In this paper, we presented an experiment aiming at testing the expressive potentialities of the MILE as a standard for computational lexicons. The fundamental

The INTERA and ECHO projects were partly intended to create a critical mass of open and linked metadata descriptions of language resources, helping researchers to understand

To this end, screens of existing mobile applications can be transformed into new pattern solutions by following the structure of the screen meta templates that were

A domain-specific language (DSL) is a programming language or executable specification language that offers, through appropriate notations and abstractions, expressive power focused

Der Beitrag stellt eine Dom¨anenspezifische Sprache (Domain-Specific Language; DSL) f¨ur die ef- fiziente, technologie¨ubergreifende Entwicklung von Web Services vor.. Ein

- Every procedure decision gate has a reference to a decision gate given by the process model and therefore has to be added to a procedure module to include

Since a very detailed draft for the language Mocol was pro- posed by Siemens VAI at the beginning of my thesis the most extensive part was the design and implementation of a

Table 2: Classification performance according to four metrics, for the small working example (left) and the TASA corpus (right), using activation (a) or prediction values (p