Using Data.Machine, how can you compose two ProcessT together that modifies two different states?

coroutine, haskell, transducer-machines

Solution

You can make a bigger state and modify each computation to take a lens into a larger composite state for the system.

p1 :: (MonadState s m, Num a) => Lens' s a -> ProcessT m a a
p1 l = repeatedly $ do
   a <- await
   l += a
   yield a

You then just need to supply the larger composite state and appropriate lenses to drive the whole thing.

Problem

Let's say I have a process that modifies an underlying state that is an `Int`: ``` p1 :: ProcessT (State Int) Int Int p1 = repeatedly $ do a <- await lift . modify $ (+a) yield a ``` And another that modifies an underlying state that is an `[Int]`: ``` p2 :: ProcessT (State [Int]) Int Bool p2 = repeatedly $ do a <- await lift . modify $ (++[a]) as <- get if length as > 3 then yield True else yield False ``` I want to compose them this way: ``` p3 = source [1...6] ~> p1 ~ p2 ``` And run them like: ``` flip runState 0 . flip runState [] . runT $ p3 ``` But I get this error: ``` Couldn't match expected type `Int' with actual type `[Int]' Expected type: ProcessT (State Int) Int c0 Actual type: ProcessT (State [Int]) Int Bool In the second argument of `(~>)', namely `p2' In the expression: source [1 .. 6] ~> p1 ~> p2 ``` Suggesting p1 and p2 should have the same type of underlying state. In fact, a little experiment shows that p1 and p2 are in fact modifying the same underlying state. How can I sidestep this?

Original source