Coroutines

Hannah Schroeter uk1o@rz.uni-karlsruhe.de
Mon, 19 Mar 2001 22:56:48 +0100


Hello!

On Mon, Mar 19, 2001 at 06:43:55PM +0100, Andreas Gruenbacher wrote:
> On Mon, 19 Mar 2001, Simon Peyton-Jones wrote:

> > Lazy evaluation *is* coroutines, in a way.

> What I had in mind was something like the following (pseudocode), which
> could easily be implemented on top of coroutines:

> class Channel c t where
> 	send    :: t -> c -> IO ()
> 	receive ::      c -> IO t

> sender :: Int -> Channel -> ...
> sender n receiver = do send n receiver
>                        return (sender (n+1) receiver)

> receiver :: Channel -> ...
> receiver sender = do i <- receive sender
>                      return (receiver sender)

> c :: Channel Int
> c = ...

> main = run_them [ sender 1 c, receiver c ]

Now, you can do this:

sender :: Int -> [Int]
sender n = n:(sender (n+1))

receiver :: [Int] -> ()
receiver (x:xs) = receiver xs

main =
	let
		sent_stuff = sender 1
		receiver_result = receiver sent_stuff
	in
		receiver_result `seq` return ()

I.e. lazy lists work like coroutine channels often enough.

You can do that a bit more abstractly:

send :: a -> [a] -> [a]
send = (:)

receive :: (a -> [a] -> result) -> [a] -> result
receive f (x:xs) = f x xs

sender n = send n $ sender (n+1)
receiver = receive $ \received_thing -> receiver

main = (as above)

Note that the definition of sender now looks not too unsimilar to
your monadic things:

sender n = send n >> sender (n+1)
 ===
sender n = do
	send n
	sender (n+1) -- your 'return' above is redundant

receiver = receive >>= \received_thing -> receiver
 ===
receiver = do
	received_thing <- receive
	receiver

Now, in fact, you could achieve this effect with a continuation+state monad
quite well (state for input, continuation as *one* way for lazy output).

> [...]

Kind regards,

Hannah.