Vorlesung: Praxis der Funktionalen Programmierung | Index

Do-Notation für Monaden

Nun ist bind (>>=) zwar der richtige Begriff, aber die Syntax erfordert doch noch einige Verrenkungen (Dollars, Lambdas). Da diese jedoch immer gleich aussehen, gibt es dafür in Haskell eine spezielle Notation. Vergleiche unser Inorder-Programm
transform :: Tree a -> State (Tree Int)
transform Leaf = return Leaf
transform (Node { left = l, right = r }) = 
    bind ( transform l ) $ \ hl ->
    bind ( next )        $ \ k  ->
    bind ( transform r ) $ \ hr ->
    return ( Node { left = hl, key = k, right = hr } )
Wir schreiben stattdessen
transform :: Tree a -> State (Tree Int)
transform Leaf = return Leaf
transform (Node { left = l, right = r }) = 
   do { hl <- transform l 
      ; k  <- next 
      ; hr <- transform r 
      ; return ( Node { left = hl, key = k, right = hr } )
      }
Aus jedem bind wird also ein Semikolon! Beachte (bestaune:) da wir die Monad-Instance selbst schreiben, indem wir die Implementierung für die Methode bind angeben, überladen wir die Semikolons. Muß man sich mal in irgendeiner anderen Sprache vorstellen!

Die Klammern und Semikolons dürfen wir sogar noch weglassen, wenn wir (wie bisher immer) alles schön untereinander schreiben.

transform (Node { left = l, right = r }) = 
   do hl <- transform l 
      k  <- next 
      hr <- transform r 
      return ( Node { left = hl, key = k, right = hr } )

Übersetzungsregeln für do

In do-Blöcken haben wir Generatoren (mit Pfeil <-), lokale Bindungen (mit let), sowie ganz am Ende einen Ausdruck, meist return.
do { x <- f   ; rest }  = bind f $ \ x -> do { rest } 
do { let x = a; rest }  = let x = a in    do { rest }
do {             exp }  = exp
Es gibt eine Sonderregelung: für Ausdrücke f :: m (), deren Wert also nicht interessiert, dürfen wir den Generator wie einen Ausdruck schreiben
do { () <- f ; rest } = do { f ; rest }
Die Ähnlichkeit zu List comprehensions ist gewollt. Früher (vorvorige Haskell-Version) hätte man sogar schreiben dürfen
transform (Node { left = l, right = r }) = 
   [ Node { left = hl, key = k, right = hr } 
   | hl <- transform l 
   , k  <- next 
   , hr <- transform r 
   ]  

best viewed with any browser


http://www.informatik.uni-leipzig.de/~joe/ mailto:joe@informatik.uni-leipzig.de