Mon, 19 Mar 2001 22:56:48 +0100
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
sent_stuff = sender 1
receiver_result = receiver sent_stuff
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
sender (n+1) -- your 'return' above is redundant
receiver = receive >>= \received_thing -> receiver
receiver = do
received_thing <- receive
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).