#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 qualified Control.Monad.Fail as Fail
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 = Fail.fail
instance Fail.MonadFail (PlanT k o m) where
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