| 7 | | The framework relies on the [wiki:monad-parallel monad-parallel] package to enable parallel execution of multiple coroutines' steps. |
| 8 | | |
| 9 | | == The lowest layer: trampoline-style nestable coroutines == |
| 10 | | |
| 11 | | This layer, implemented by the Control.Concurrent.Coroutine module, provides a limited coroutine functionality in Haskell. The centerpiece of the approach is the monad transformer Coroutine, that transforms an arbitrary monadic computation into a suspendable and resumable one. The basic definition is simple: |
| 12 | | |
| 13 | | {{{ |
| 14 | | newtype Coroutine s m r = Coroutine {resume :: m (CoroutineState s m r)} |
| 15 | | |
| 16 | | data CoroutineState s m r = Done r | Suspend! (s (Coroutine s m r)) |
| 17 | | |
| 18 | | instance (Functor s, Monad m) => Monad (Coroutine s m) where |
| 19 | | return x = Coroutine (return (Done x)) |
| 20 | | t >>= f = Coroutine (resume t >>= apply f) |
| 21 | | where apply f (Done x) = resume (f x) |
| 22 | | apply f (Suspend s) = return (Suspend (fmap (>>= f) s)) |
| 23 | | }}} |
| 24 | | |
| 25 | | The Coroutine transformer type is parameterized by a functor. Here is an example of one functor particularly useful for a Coroutine computation: |
| 26 | | |
| 27 | | {{{ |
| 28 | | data Yield x y = Yield x y |
| 29 | | instance Functor (Yield x) where |
| 30 | | fmap f (Yield x y) = Yield x (f y) |
| 31 | | }}} |
| | 7 | The framework relies on the following packages: |
| | 8 | * [wiki:monad-parallel monad-parallel] to enable parallel execution of monadic computations, and |
| | 9 | * [wiki:monad-coroutine monad-coroutine] to enable the same monadic computations to suspend and resume each other. |