packages feed

imsos-monad-0.1.0.0: src/Control/Monad/IMSOS.hs

{-# LANGUAGE UndecidableInstances
  , FlexibleInstances
  , FlexibleContexts
  , MultiParamTypeClasses
#-}

module Control.Monad.IMSOS 
  (MonadIMSOS(..), runIMSOS, yieldIMSOS
  ,tell
  ,local, reader
  ,get, put, state
  ,fail, throwError, catchError
  ) where

import Control.Applicative (Alternative(..))
import Control.Monad.Error.Class
import Control.Monad.Reader (MonadReader(..))
import Control.Monad.State  (MonadState(..))
import Control.Monad.Writer (MonadWriter(..))
import Control.Monad (ap)

newtype MonadIMSOS r s w me e a = MonadIMSOS (r -> s -> me e (a, s, w))

instance Functor (me e) => Functor (MonadIMSOS r s w me e) where
  fmap f (MonadIMSOS m) = MonadIMSOS m'
    where m' r s = modify <$> m r s
           where modify (a, s', w) = (f a, s', w)

instance (MonadError e (me e), Monad (me e), Monoid w)
    => Monad (MonadIMSOS r s w me e) where
  (MonadIMSOS p) >>= m = MonadIMSOS $ \r1 s1  -> do
     (a, s2, w2) <- p r1 s1
     let MonadIMSOS q = m a
     (b, s3, w3) <- q r1 s2
     return (b, s3, w2 <> w3)

instance (MonadError e (me e), Monad (me e), Monoid w)
    => Applicative (MonadIMSOS r s w me e) where
  pure a = MonadIMSOS m
    where m _ s = pure (a, s, mempty)
  (<*>) = ap

instance (MonadError e (me e), Monad (me e), Alternative (me e), Monoid w)
    => Alternative (MonadIMSOS r s w me e) where
  empty = MonadIMSOS (\_ _ -> empty)
  (MonadIMSOS p) <|> (MonadIMSOS q) = MonadIMSOS m
    where m r s = p r s `catchError` \_ -> q r s
 
--instance (MonadError e (me e), Monad (me e), Monoid w)
--    => MonadPlus (MonadIMSOS r s w me e)

instance (MonadError String (me String), Monad (me String), Monoid w)
    => MonadFail (MonadIMSOS r s w me String) where
  fail = throwError

instance (MonadError e (me e), Monad (me e), Monoid w)
    => MonadReader r (MonadIMSOS r s w me e) where
  ask = MonadIMSOS m 
    where m r s = pure (r, s, mempty)
  local f (MonadIMSOS p) = MonadIMSOS m
    where m r s = p (f r) s

instance (MonadError e (me e), Monad (me e), Monoid w)
    => MonadState s (MonadIMSOS r s w me e) where
  state act = MonadIMSOS m
    where m _ s = pure (a, s', mempty)
           where (a, s') = act s

instance (MonadError e (me e), Monad (me e), Monoid w)
    => MonadWriter w (MonadIMSOS r s w me e) where
  tell w = MonadIMSOS m
    where m _ s = pure ((), s, w)
  listen (MonadIMSOS p) = MonadIMSOS m
    where m r s = p r s >>= \(a, s', w) -> pure ((a,w), s', w)
  pass (MonadIMSOS p) = MonadIMSOS m
    where m r s = p r s >>= \((a,f), s', w) -> pure (a, s', f w)

instance (MonadError e (me e), Monad (me e), Monoid w)
    => MonadError e (MonadIMSOS r s w me e) where
  throwError e = MonadIMSOS m
    where m _ _ = throwError e
  catchError (MonadIMSOS p) h = MonadIMSOS m
    where m r s = p r s `catchError` \e -> 
                  let MonadIMSOS q = h e
                  in q r s -- continues with a state as if p not executed

runIMSOS :: r -> s -> MonadIMSOS r s w me e a -> me e (a, s, w)
runIMSOS r s (MonadIMSOS f) = f r s

yieldIMSOS :: Functor (me e) => 
  r -> s -> ((a, s, w) -> y) -> MonadIMSOS r s w me e a -> me e y
yieldIMSOS r s toyield m = toyield <$> runIMSOS r s m