Links und Funktionen
Sprachumschaltung

Navigationspfad
Sie sind hier: Startseite / Lehre / SS 2012 / Funktionale Programmierung / Folien / Monad Transformers


Inhaltsbereich

Monad Transformers

Funktionale Programmierung Beispiele zu Monadenkomposition (.hs Datei)

Haskell source code icon MonadTrans.hs — Haskell source code, 4 KB (4397 bytes)

Dateiinhalt

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-}

import Control.Monad
{-
import Control.Monad.Trans
import Control.Monad.Error
import Control.Monad.State
import Control.Monad.Reader
import Control.Monad.Writer
-}

-- Monaden-Komposition
----------------------------------------------------------------------

-- error : Error    a = Maybe a / Either String a
-- reader: Reader r a = r -> a
-- state : State  s a = s -> (a, s)
-- writer: Writer o a = (a, o)
-- I/O   : IO       a

-- Wenn wir mehr als 1 Effekt wollen, m"ussen wir Monaden komponieren:

-- Beispiel 1: error + reader
--
-- 1. M"oglichkeit: m a = Error (Reader r a)

newtype ER r a = ER { runER :: Either String (r -> a) }

instance Monad (ER r) where
  return a = ER $ Right $ \ r -> a
  m >>= k  = ER $
    case runER m of
      Left err -> Left err
      Right f  -> Right $ \ r ->
        let a = f r in
        case runER (k a) of
          Left err -> error "what now?  Already decided there would be no error"
          Right g -> g r

-- das war wohl falsch herum
--
-- 2. M"oglichkeit: m a = Reader r (Error a)

newtype RE r a = RE { runRE :: r -> Either String a }

instance Monad (RE r) where
  return a = RE $ \ r -> Right a
  m >>= k  = RE $ \ r ->
    case runRE m r of
      Left err -> Left err
      Right a  ->
        case runRE (k a) r of
          Left err -> Left err
          Right b  -> Right b

-- Beispiel 2: reader + state

-- 1. M"oglichkeit: m a = State s (Reader r a)

newtype SR s r a = SR { runSR :: s -> (r -> a, s) }

instance Monad (SR s r) where
  return a = SR $ \ s -> (\ r -> a, s)
  m >>= k  = SR $ \ s ->
    let (f, s') = runSR m s
    in  (\ r -> let a        = f r
                    (g, s'') = runSR (k a) s'
                    b        = g r
                in  b  -- need to discard last state s''
        , s')          -- need to return butlast state s'

-- 2. M"oglichkeit: m a = Reader r (State s a)

newtype RS r s a = RS { runRS :: r -> s -> (a, s) }

instance Monad (RS r s) where
  return a = RS $ \ r s -> (a, s)
  m >>= k  = RS $ \ r s ->
    let (a, s') = runRS m r s
    in  runRS (k a) r s'

-- Lektion: nicht jede Komposition von Monaden ist wieder eine Monade

-- Richtige Komposition:
-- au"sen      : Reader
-- innen       : Error
-- in der Mitte: State

-- Reader r (State s (Maybe a)) = r -> s -> (Maybe a, s)


-- Monaden-Transformer
----------------------------------------------------------------------

-- Wir wollen nicht f"ur jede Komposition von Monaden wieder
-- return und (>>=) h"andisch definieren m"ussen.

-- Ein Monaden-Transformer nimmt eine Monade und macht wieder eine daraus

-- Beispiel: Reader (au"sen)

newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }

instance Monad m => Monad (ReaderT r m) where
  return a = ReaderT $ \ r -> return a
  m >>= k  = ReaderT $ \ r -> do
    a <- runReaderT m r
    runReaderT (k a) r

-- Beispiel: Error (innen)

newtype ErrorT e m a = ErrorT { runErrorT :: m (Either e a) }

instance Monad m => Monad (ErrorT e m) where
  return a = ErrorT $ return (Right a)
  m >>= k  = ErrorT $ do
    ma <- runErrorT m
    case ma of
      Left e  -> return (Left e)
      Right a -> do
        mb <- runErrorT (k a)
        case mb of
          Left e  -> return (Left e)
          Right b -> return (Right b)

-- Monad Lifting
----------------------------------------------------------------------

-- Wie erreichen wir die Funktionalit"at der inneren Monade

class MonadTrans t where
  lift :: Monad m => m a -> t m a

-- Gesetze

-- lift . return = return

-- lift (m >>= f) = lift m >>= (lift . f)

instance MonadTrans (ReaderT r) where
  lift m = ReaderT $ \ r -> m

instance MonadTrans (ErrorT e) where
  lift m = ErrorT $ do
    a <- m
    return (Right a)

-- Beispiel: IO mit Reader

class Monad m => MonadReader r m | m -> r where
  ask   :: m r
  local :: (r -> r) -> m a -> m a

instance Monad m => MonadReader r (ReaderT r m) where
  ask       = ReaderT $ \ r -> return r
  local f m = ReaderT $ \ r -> runReaderT m (f r)


test :: ReaderT Bool IO ()
test = do
  b <- ask
  lift $ putStrLn ("Mein Argument hat den Wert " ++ show b)

main :: IO ()
main = runReaderT test True
















{-
class Monad m => MonadError e m | m -> e where


instance (MonadTrans t, MonadReader m) => MonadReader (t m) where
  ask       = lift $ ask
  local f m = local f ???
-}

Artikelaktionen


Funktionsleiste