module Control.Remote.Monad
(
RemoteMonad
, command
, procedure
, RunMonad(runMonad)
, runWeakMonad
, runStrongMonad
, runApplicativeMonad
, runMonadSkeleton
) where
import Control.Monad.Trans.Class
import Control.Monad.Trans.State.Strict
import qualified Control.Remote.Applicative as A
import Control.Remote.Monad.Packet.Applicative as A
import Control.Remote.Monad.Packet.Weak as Weak
import Control.Remote.Monad.Packet.Strong as Strong
import Control.Remote.Monad.Types
import Control.Natural
command :: c -> RemoteMonad c p ()
command = Appl . A.command
procedure :: p a -> RemoteMonad c p a
procedure = Appl . A.procedure
class RunMonad f where
runMonad :: (Monad m) => (f c p :~> m) -> (RemoteMonad c p :~> m)
instance RunMonad WeakPacket where
runMonad = runWeakMonad
instance RunMonad StrongPacket where
runMonad = runStrongMonad
instance RunMonad ApplicativePacket where
runMonad = runApplicativeMonad
runMonadSkeleton :: (Monad m) => (RemoteApplicative c p :~> m) -> (RemoteMonad c p :~> m)
runMonadSkeleton f = nat $ \ case
Appl g -> run f g
Bind g k -> run f g >>= \ a -> runMonadSkeleton f # (k a)
runWeakMonad :: (Monad m) => (WeakPacket c p :~> m) -> (RemoteMonad c p :~> m)
runWeakMonad = runMonadSkeleton . A.runWeakApplicative
runStrongMonad :: forall m c p . (Monad m) => (StrongPacket c p :~> m) -> (RemoteMonad c p :~> m)
runStrongMonad (Nat f) = nat $ \ p -> do
(r,HStrongPacket h) <- runStateT (go2 p) (HStrongPacket id)
f $ h $ Strong.Done
return r
where
go2 :: forall a . RemoteMonad c p a -> StateT (HStrongPacket c p) m a
go2 (Appl app) = go' app
go2 (Bind app k) = go' app >>= \ a -> go2 (k a)
go' :: forall a . RemoteApplicative c p a -> StateT (HStrongPacket c p) m a
go' (RemoteApplicative m) = go m
go :: forall a . ApplicativePacket c p a -> StateT (HStrongPacket c p) m a
go (A.Pure a) = return a
go (A.Command g c) = do
r <- go g
modify (\ (HStrongPacket cs) -> HStrongPacket (cs . Strong.Command c))
return r
go (A.Procedure g p) = do
r1 <- go g
HStrongPacket cs <- get
put (HStrongPacket id)
r2 <- lift $ f $ cs $ Strong.Procedure $ p
return $ r1 r2
runApplicativeMonad :: forall m c p . (Monad m) => (A.ApplicativePacket c p :~> m) -> (RemoteMonad c p :~> m)
runApplicativeMonad (Nat f) = nat $ \ p -> do
(r,h) <- runStateT (go2 p) (pure ())
f $ h
return r
where
go2 :: forall a . RemoteMonad c p a -> StateT (A.ApplicativePacket c p ()) m a
go2 (Appl app) = go' app
go2 (Bind app k) = go' app >>= \ a -> go2 (k a)
go' :: forall a . RemoteApplicative c p a -> StateT (A.ApplicativePacket c p ()) m a
go' (RemoteApplicative m) = go m
go :: forall a . ApplicativePacket c p a -> StateT (A.ApplicativePacket c p ()) m a
go ap = case A.superCommand ap of
Nothing -> do
ap' <- get
put (pure ())
lift $ f $ (ap' *> ap)
Just a -> do
modify (\ ap' -> ap' <* ap)
return a