#ifndef MIN_VERSION_mtl
#define MIN_VERSION_mtl(x,y,z) 0
#endif
module Data.Machine.Plan
(
Plan
, runPlan
, PlanT(..)
, yield
, maybeYield
, await
, stop
, awaits
, exhaust
) where
import Control.Applicative
import Control.Category
import Control.Monad (MonadPlus(..))
import Control.Monad.Trans.Class
import Control.Monad.IO.Class
import Control.Monad.State.Class
import Control.Monad.Reader.Class
import Control.Monad.Error.Class
import Control.Monad.Writer.Class
import Data.Functor.Identity
import Prelude hiding ((.),id)
newtype PlanT k o m a = PlanT
{ runPlanT :: forall r.
(a -> m r) ->
(o -> m r -> m r) ->
(forall z. (z -> m r) -> k z -> m r -> m r) ->
m r ->
m r
}
type Plan k o a = forall m. PlanT k o m a
runPlan :: PlanT k o Identity a
-> (a -> r)
-> (o -> r -> r)
-> (forall z. (z -> r) -> k z -> r -> r)
-> r
-> r
runPlan m kp ke kr kf = runIdentity $ runPlanT m
(Identity . kp)
(\o (Identity r) -> Identity (ke o r))
(\f k (Identity r) -> Identity (kr (runIdentity . f) k r))
(Identity kf)
instance Functor (PlanT k o m) where
fmap f (PlanT m) = PlanT $ \k -> m (k . f)
instance Applicative (PlanT k o m) where
pure a = PlanT (\kp _ _ _ -> kp a)
m <*> n = PlanT $ \kp ke kr kf -> runPlanT m (\f -> runPlanT n (\a -> kp (f a)) ke kr kf) ke kr kf
m *> n = PlanT $ \kp ke kr kf -> runPlanT m (\_ -> runPlanT n kp ke kr kf) ke kr kf
m <* n = PlanT $ \kp ke kr kf -> runPlanT m (\a -> runPlanT n (\_ -> kp a) ke kr kf) ke kr kf
instance Alternative (PlanT k o m) where
empty = PlanT $ \_ _ _ kf -> kf
PlanT m <|> PlanT n = PlanT $ \kp ke kr kf -> m kp ke kr (n kp ke kr kf)
instance Monad (PlanT k o m) where
return = pure
PlanT m >>= f = PlanT (\kp ke kr kf -> m (\a -> runPlanT (f a) kp ke kr kf) ke kr kf)
(>>) = (*>)
fail _ = PlanT (\_ _ _ kf -> kf)
instance MonadPlus (PlanT k o m) where
mzero = empty
mplus = (<|>)
instance MonadTrans (PlanT k o) where
lift m = PlanT (\kp _ _ _ -> m >>= kp)
instance MonadIO m => MonadIO (PlanT k o m) where
liftIO m = PlanT (\kp _ _ _ -> liftIO m >>= kp)
instance MonadState s m => MonadState s (PlanT k o m) where
get = lift get
put = lift . put
#if MIN_VERSION_mtl(2,1,0)
state f = PlanT $ \kp _ _ _ -> state f >>= kp
#endif
instance MonadReader e m => MonadReader e (PlanT k o m) where
ask = lift ask
#if MIN_VERSION_mtl(2,1,0)
reader = lift . reader
#endif
local f m = PlanT $ \kp ke kr kf -> local f (runPlanT m kp ke kr kf)
instance MonadWriter w m => MonadWriter w (PlanT k o m) where
#if MIN_VERSION_mtl(2,1,0)
writer = lift . writer
#endif
tell = lift . tell
listen m = PlanT $ \kp ke kr kf -> runPlanT m ((kp =<<) . listen . return) ke kr kf
pass m = PlanT $ \kp ke kr kf -> runPlanT m ((kp =<<) . pass . return) ke kr kf
instance MonadError e m => MonadError e (PlanT k o m) where
throwError = lift . throwError
catchError m k = PlanT $ \kp ke kr kf -> runPlanT m kp ke kr kf `catchError` \e -> runPlanT (k e) kp ke kr kf
yield :: o -> Plan k o ()
yield o = PlanT (\kp ke _ _ -> ke o (kp ()))
maybeYield :: Maybe o -> Plan k o ()
maybeYield = maybe stop yield
await :: Category k => Plan (k i) o i
await = PlanT (\kp _ kr kf -> kr kp id kf)
awaits :: k i -> Plan k o i
awaits h = PlanT $ \kp _ kr -> kr kp h
stop :: Plan k o a
stop = empty
exhaust :: Monad m => m (Maybe a) -> PlanT k a m ()
exhaust f = do (lift f >>= maybeYield); exhaust f