Weiter Zurück Inhalt

5. Kombinieren von Monads

Es ist einfach möglich, die verschiedenen Mondads, die hier vorgestellt wurden, zu kombinieren. In diesem Beispiel wird das Status-Monad mit dem IO-Monad kombiniert. Eine Berechnung in dem IOState-Monad ist eine Berechnung in dem IO-Monad, die einen Ausgangsstatus in einen Endstatus überführt.

data IOState a b = IOState ( a -> IO (a, b) )

instance Monad (IOState a) where
    return v = IOState ( \s -> return (s, v))

    IOState f1 >>= f2
      = IOState ( \st1 -> do (st2, r) <- f1 st1
                             let (IOState trans ) = f2 r in 
                               trans st2 )

readState    :: IOState a a
readState    =  IOState   (\st -> return (st, st) )

writeState   :: a -> IOState a ()
writeState s = IOState (\_ -> return ( s, () ))

Bei readState und writeState ist zu beachten, daß das return zu dem IO-Monad gehört.

liftIO fügt eine Berechnung in dem IO-Monad in das IOState-Monad ein.

liftIO       :: IO b -> IOState a b
liftIO ioa   =  IOState ( \s -> do a <- ioa
                                   return (s, a) )

extractIO    :: a -> IOState a b -> IO b
extractIO init (IOState f) 
             =  do ( st, res ) <- f init
                   return res

> foo x = do
>   writeState x
>   while ( do { nr <- readState; return (nr /= 1) } ) ( do 
>     nr <- readState
>     liftIO (putStrLn (show nr))
>     let nr´ = if ( nr ´mod´ 2 == 0 ) then (nr ´div´ 2) 
>                                      else (3 * nr + 1)
>     writeState nr´
>     return () 
>    )
> extractIO 0 ( foo 10 )

Durch die Verwendung des IOState-Monads ist es möglich, imperative Programme zu schreiben, die sich kaum von Programmen in normalen imperativen Sprachen unterscheiden.


Weiter Zurück Inhalt