module Control.Monatron.Monad (
  State, Writer, Reader, Exception, Cont,
  state,writer,reader,exception,cont,
  runState, runWriter, runReader, runException, runCont,
  Id(..), Lift(..)
) where
  

import Control.Monatron.Transformer
import Control.Monad
import Control.Monad.Fix

newtype Id a   = Id {runId :: a}
data    Lift a = L  {runLift :: a}

type State s      = StateT s Id
type Writer w     = WriterT w Id
type Reader r     = ReaderT r Id
type Exception x  = ExcT x Id
type Cont r       = ContT r Id

state :: (s -> (a, s)) -> State s a
state st = stateT $ \s -> Id $ st s

runState :: s -> State s a -> (a,s)
runState s = runId. runStateT s

writer :: Monoid w => (a,w) -> Writer w a
writer = writerT . Id

runWriter :: Monoid w => Writer w a -> (a,w)
runWriter = runId. runWriterT

reader :: (r -> a) -> Reader r a
reader e = readerT $ \r -> Id (e r)

runReader :: r -> Reader r a -> a
runReader r = runId . runReaderT r

exception :: Either x a -> Exception x a
exception = excT . Id

runException :: Exception x a -> Either x a
runException = runId. runExcT

cont :: ((a -> r) -> r) -> Cont r a
cont c = contT $ \k -> Id $ c (runId . k)

runCont :: (a -> r) -> Cont r a  -> r
runCont k = runId. runContT (Id. k)

instance Monad Id where
    return  = Id
    fail    = error
    m >>= f = f (runId m)

instance Monad Lift where
  return x  = L x
  fail x    = error x
  L x >>= k = k x

instance Functor Id   where fmap = liftM
instance Functor Lift where fmap = liftM

instance MonadFix Id   where mfix f = let m = f (runId m)   in m
instance MonadFix Lift where mfix f = let m = f (runLift m) in m