Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

composing machines in a cycle

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?

like image 452
marcosh Avatar asked Oct 17 '25 23:10

marcosh


1 Answers

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
like image 138
Li-yao Xia Avatar answered Oct 19 '25 11:10

Li-yao Xia



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!