module Data.Machine.Pipe where
import Control.Monad
import Data.Void
import Data.Machine.Plan
import Data.Machine.Type
infixl 8 >~>
infixl 7 >+>
infixl 7 >>~
infixr 6 +>>
data Exchange a' a b' b c where
Request :: a' -> Exchange a' a b' b a
Respond :: b -> Exchange a' a b' b b'
type Proxy a' a b' b m c = MachineT m (Exchange a' a b' b) c
type Effect m r = Proxy Void () () Void m r
type Client a' a m r = Proxy a' a () Void m r
type Server b' b m r = Proxy Void () b' b m r
type Effect' m r = forall x' x y' y . Proxy x' x y' y m r
type Server' b' b m r = forall x' x . Proxy x' x b' b m r
type Client' a' a m r = forall y' y . Proxy a' a y' y m r
request :: a' -> PlanT (Exchange a' a y' y) o m a
request a = awaits (Request a)
respond :: a -> PlanT (Exchange x' x a' a) o m a'
respond a = awaits (Respond a)
push :: Monad m => a -> Proxy a' a a' a m r
push = construct . go
where
go = respond >=> request >=> go
(>~>) :: Monad m
=> (_a -> Proxy a' a b' b m r)
-> (b -> Proxy b' b c' c m r)
-> _a -> Proxy a' a c' c m r
(fa >~> fb) a = fa a >>~ fb
(>>~) :: Monad m
=> Proxy a' a b' b m r
-> (b -> Proxy b' b c' c m r)
-> Proxy a' a c' c m r
pm >>~ fb = MachineT $ runMachineTpm >>= \p ->
case p of
Stop -> return Stop
Yield r n -> return $ Yield r (n >>~ fb)
Await k (Request a') ff -> return $ Await (\a -> k a >>~ fb) (Request a') (ff >>~ fb)
Await k (Respond b) _ -> runMachineT (k +>> fb b)
pull :: Monad m => a' -> Proxy a' a a' a m r
pull = construct . go
where
go = request >=> respond >=> go
(>+>) :: Monad m
=> (b' -> Proxy a' a b' b m r)
-> (_c' -> Proxy b' b c' c m r)
-> _c' -> Proxy a' a c' c m r
(fb' >+> fc') c' = fb' +>> fc' c'
(+>>) :: Monad m
=> (b' -> Proxy a' a b' b m r)
-> Proxy b' b c' c m r
-> Proxy a' a c' c m r
fb' +>> pm = MachineT $ runMachineT pm >>= \p ->
case p of
Stop -> return Stop
Yield r n -> return $ Yield r (fb' +>> n)
Await k (Request b') _ -> runMachineT (fb' b' >>~ k)
Await k (Respond c) ff -> return $ Await (\c' -> fb' +>> k c') (Respond c) (fb' +>> ff)
absurdExchange :: Exchange Void a b Void t -> c
absurdExchange (Request z) = absurd z
absurdExchange (Respond z) = absurd z
runEffect :: Monad m => Effect m o -> m [o]
runEffect (MachineT m) = m >>= \v ->
case v of
Stop -> return []
Yield o n -> liftM (o:) (runEffect n)
Await _ y _ -> absurdExchange y
runEffect_ :: Monad m => Effect m o -> m ()
runEffect_ (MachineT m) = m >>= \v ->
case v of
Stop -> return ()
Yield _ n -> runEffect_ n
Await _ y _ -> absurdExchange y