{-# LANGUAGE CPP #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
#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)
{-# INLINE runPlan #-}
instance Functor (PlanT k o m) where
fmap f (PlanT m) = PlanT $ \k -> m (k . f)
{-# INLINE fmap #-}
instance Applicative (PlanT k o m) where
pure a = PlanT (\kp _ _ _ -> kp a)
{-# INLINE pure #-}
m <*> n = PlanT $ \kp ke kr kf -> runPlanT m (\f -> runPlanT n (\a -> kp (f a)) ke kr kf) ke kr kf
{-# INLINE (<*>) #-}
m *> n = PlanT $ \kp ke kr kf -> runPlanT m (\_ -> runPlanT n kp ke kr kf) ke kr kf
{-# INLINE (*>) #-}
m <* n = PlanT $ \kp ke kr kf -> runPlanT m (\a -> runPlanT n (\_ -> kp a) ke kr kf) ke kr kf
{-# INLINE (<*) #-}
instance Alternative (PlanT k o m) where
empty = PlanT $ \_ _ _ kf -> kf
{-# INLINE empty #-}
PlanT m <|> PlanT n = PlanT $ \kp ke kr kf -> m kp ke kr (n kp ke kr kf)
{-# INLINE (<|>) #-}
instance Monad (PlanT k o m) where
return = pure
{-# INLINE return #-}
PlanT m >>= f = PlanT (\kp ke kr kf -> m (\a -> runPlanT (f a) kp ke kr kf) ke kr kf)
{-# INLINE (>>=) #-}
(>>) = (*>)
{-# INLINE (>>) #-}
fail = Fail.fail
instance Fail.MonadFail (PlanT k o m) where
fail _ = PlanT (\_ _ _ kf -> kf)
instance MonadPlus (PlanT k o m) where
mzero = empty
{-# INLINE mzero #-}
mplus = (<|>)
{-# INLINE mplus #-}
instance MonadTrans (PlanT k o) where
lift m = PlanT (\kp _ _ _ -> m >>= kp)
{-# INLINE lift #-}
instance MonadIO m => MonadIO (PlanT k o m) where
liftIO m = PlanT (\kp _ _ _ -> liftIO m >>= kp)
{-# INLINE liftIO #-}
instance MonadState s m => MonadState s (PlanT k o m) where
get = lift get
{-# INLINE get #-}
put = lift . put
{-# INLINE put #-}
#if MIN_VERSION_mtl(2,1,0)
state f = PlanT $ \kp _ _ _ -> state f >>= kp
{-# INLINE state #-}
#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