I am working with the machines library and I have three Processes
foo :: Process a b
bar :: Process b a
baz :: Process b c
I would like to compose them such that both bar and baz use the output of foo as input. Moreover, and this is the part I'm struggling with, I would like to fed the output of bar back into foo, forming a cycle. Any hints on how to do it?
First you can use ~> to compose processes sequentially (Process x y -> Process y z -> Process x z), so the problem reduces to interpreting Process a a, which you can do with a recursive function carrying a buffer. The buffer gets extended by Yield and consumed by Await. There is some arbitrariness in how you want to handle Await on an empty buffer; here I just take the "no input" continuation and resume normally.
{-# LANGUAGE GADTs #-}
import Data.Machine
import Data.Machine.Process
loop :: Monad m => ProcessT m a a -> m ()
loop p = go [] p where
go :: Monad m => [a] -> ProcessT m a a -> m ()
go buffer p = runMachineT p >>= \s -> case s of
Stop -> pure ()
Yield o p -> go (buffer ++ [o]) p
Await p1 Refl p0 ->
case buffer of
[] -> go [] p0
i : buffer' -> go buffer' (p1 i)
loop3 :: Monad m => ProcessT m a b -> ProcessT m b c -> ProcessT m c a -> m ()
loop3 x y z = loop (x ~> y ~> z)
example :: ProcessT IO String String
example =
encased (Yield "world" (
encased (Await (\name ->
MachineT (putStrLn ("Hello " ++ name ++ "!") >> pure Stop)) Refl (error "No input"))))
main :: IO ()
main = loop example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With