{-# OPTIONS -XRank2Types #-}
module Control.Monatron.Operations (
ExtModel, Model, AlgModel, toAlg, liftModel, liftAlgModel, liftExtModel,
StateOp(..), modelStateT, getX, putX,
ReaderOp(..), modelReaderT, askX, inEnvX, localX,
WriterOp(..), modelWriterT, traceX,
ThrowOp(..),HandleOp(..), modelThrowExcT, modelHandleExcT,
modelThrowIO, modelHandleIO, throwX, handleX,
ContOp(..), modelContT, callccX, callCCX, abortX,
StepOp(..), stepX, modelStepT,
ListOp(..), modelListT, zeroListX, plusListX,
module Control.Monatron.Transformer
) where
import Control.Monatron.Codensity
import Control.Monatron.Transformer
import qualified Control.Exception as IO (throwIO,catch,SomeException)
type ExtModel f g m = forall a. f (m (g a)) -> m a
type Model f m = forall a. f (m a) -> m a
type AlgModel f m = forall a. f a -> m a
toAlg :: (Functor f, Monad m) => Model f m -> AlgModel f (Codensity m)
toAlg op t = codensity $ \k -> op (fmap k t)
liftModel :: (Functor f, Monad m, Functor m, FMonadT t, Monad (t (Codensity m))) =>
Model f m -> Model f (t m)
liftModel op = tmap runCodensity . join . lift . toAlg op . fmap (tmap lift)
liftAlgModel :: (MonadT t, Monad m, Functor f) => AlgModel f m -> AlgModel f (t m)
liftAlgModel op = lift . op
liftExtModel :: ( Functor f, Functor g, Monad m, Functor m,
MMonadT t, Functor (t f), Functor (t m)) =>
ExtModel f g m -> ExtModel f g (t m)
liftExtModel op = tmap (op . fmap deComp . deComp) .
monoidalT . flift . fmap (monoidalT . fmap flift)
data StateOp s a = Get (s -> a) | Put s a
instance Functor (StateOp s) where
fmap f (Get g) = Get (f . g)
fmap f (Put s a) = Put s (f a)
modelStateT :: Monad m => AlgModel (StateOp s) (StateT s m)
modelStateT (Get g) = stateT (\s -> return (g s, s))
modelStateT (Put s a) = stateT (\_ -> return (a, s))
getX :: Monad m => AlgModel (StateOp s) m -> m s
getX op = op $ Get id
putX :: Monad m => AlgModel (StateOp s) m -> s -> m ()
putX op s = op $ Put s ()
data ReaderOp s a = Ask (s -> a) | InEnv s a
instance Functor (ReaderOp s) where
fmap f (Ask g) = Ask (f . g)
fmap f (InEnv s a) = InEnv s (f a)
modelReaderT :: Monad m => Model (ReaderOp s) (ReaderT s m)
modelReaderT (Ask g) = readerT (\s -> runReaderT s (g s))
modelReaderT (InEnv s a) = readerT (\_ -> runReaderT s a)
askX :: Monad m => Model (ReaderOp s) m -> m s
askX op = op $ Ask return
inEnvX :: Monad m => Model (ReaderOp s) m -> s -> m a -> m a
inEnvX op s m = op $ InEnv s m
localX :: Monad m => Model (ReaderOp z) m -> (z -> z) -> m a -> m a
localX m f t = do z <- askX m
inEnvX m (f z) t
data ThrowOp x a = Throw x
data HandleOp x a = Handle a (x -> a)
instance Functor (ThrowOp x) where
fmap _ (Throw x) = Throw x
instance Functor (HandleOp x) where
fmap f (Handle a h) = Handle (f a) (f . h)
modelThrowExcT :: Monad m => AlgModel (ThrowOp x) (ExcT x m)
modelThrowExcT (Throw x) = excT (return (Left x))
modelHandleExcT :: Monad m => Model (HandleOp x) (ExcT x m)
modelHandleExcT (Handle m h) = excT (runExcT m >>= \exa -> case exa of
Left x -> runExcT (h x)
Right a -> return (Right a))
modelThrowIO :: AlgModel (ThrowOp IO.SomeException) IO
modelThrowIO (Throw x) = IO.throwIO x
modelHandleIO :: Model (HandleOp IO.SomeException) IO
modelHandleIO (Handle m h) = IO.catch m h
throwX :: Monad m => AlgModel (ThrowOp x) m -> x -> m a
throwX op x = op $ Throw x
handleX :: Monad m => Model(HandleOp x) m -> m a -> (x -> m a) -> m a
handleX op m h = op $ Handle m h
data WriterOp w a = Trace w a
instance Functor (WriterOp w) where
fmap f (Trace w a) = Trace w (f a)
modelWriterT :: (Monad m, Monoid w) => AlgModel (WriterOp w) (WriterT w m)
modelWriterT (Trace w a) = writerT (return (a,w))
traceX :: (Monad m) => AlgModel (WriterOp w) m -> w -> m ()
traceX op w = op $ Trace w ()
data ContOp r a = Abort r | CallCC ((a -> r) -> a)
instance Functor (ContOp r) where
fmap _ (Abort r) = Abort r
fmap f (CallCC k) = CallCC (\c -> f (k (c . f)))
modelContT :: Monad m => AlgModel (ContOp (m r)) (ContT r m)
modelContT (Abort mr) = contT $ \_ -> mr
modelContT (CallCC k) = contT $ \c -> c (k c)
abortX :: Monad m => AlgModel (ContOp r) m -> r -> m a
abortX op r = op (Abort r)
callCCX :: Monad m => AlgModel (ContOp r) m -> ((a -> r) -> a) -> m a
callCCX op f = op (CallCC f)
callccX :: Monad m => AlgModel (ContOp r) m -> ((a -> m b) -> m a) -> m a
callccX op f = join $ callCCX op (\k -> f (\x -> abortX op (k (return x))))
newtype StepOp f x = StepOp (f x)
instance (Functor f) => Functor (StepOp f) where
fmap h (StepOp fa) = StepOp (fmap h fa)
modelStepT :: (Functor f, Monad m) => Model (StepOp f) (StepT f m)
modelStepT (StepOp fa) = stepT (return (Right fa))
stepX :: (Monad m) => Model (StepOp f) m -> f (m x) -> m x
stepX op = op . StepOp
data ListOp a = ZeroList | PlusList a a
instance Functor ListOp where
fmap _ ZeroList = ZeroList
fmap f (PlusList a b) = PlusList (f a) (f b)
modelListT :: Monad m => AlgModel ListOp (ListT m)
modelListT ZeroList = emptyL
modelListT (PlusList t u) = appendL (return t) (return u)
zeroListX :: Monad m => AlgModel ListOp m -> m a
zeroListX op = op ZeroList
plusListX :: Monad m => AlgModel ListOp m -> m a -> m a -> m a
plusListX op t u = join $ op (PlusList t u)