This module defines the Coroutine
monad transformer.
A Coroutine
monadic computation can suspend
its execution at any time, returning control to its invoker. The
returned coroutine suspension is a Functor
containing the resumption of the coroutine. Here is an example of a
coroutine in the IO
monad that suspends computation using the functor Yield
from the
Control.Monad.Coroutine.SuspensionFunctors module:
producer :: Coroutine (Yield Int) IO String producer = do yield 1 lift (putStrLn "Produced one, next is four.") yield 4 return "Finished"
To continue the execution of a suspended Coroutine
, apply its resume
method. The easiest way to run a coroutine
to completion is by using the pogoStick
function, which keeps resuming the coroutine in trampolined style until it
completes. Here is an example of pogoStick
applied to the producer example above:
printProduce :: Show x => Coroutine (Yield x) IO r > IO r printProduce producer = pogoStick (\(Yield x cont) > lift (print x) >> cont) producer
Multiple concurrent coroutines can be run as well, and this module provides two different ways. Functions seesaw
and seesawSteps
can be used to run two interleaved computations. Another possible way is to use the functions
couple
or merge
to weave together steps of different coroutines into a single coroutine, which can then be
executed by pogoStick
.
For other uses of trampolinestyle coroutines, see
Trampolined Style  Ganz, S. E. Friedman, D. P. Wand, M, ACM SIGPLAN NOTICES, 1999, VOL 34; NUMBER 9, pages 1827
and
The Essence of Multitasking  William L. Harrison, Proceedings of the 11th International Conference on Algebraic Methodology and Software Technology, volume 4019 of Lecture Notes in Computer Science, 2006
 newtype Coroutine s m r = Coroutine {}
 type CoroutineStepResult s m r = Either (s (Coroutine s m r)) r
 suspend :: (Monad m, Functor s) => s (Coroutine s m x) > Coroutine s m x
 mapMonad :: forall s m m' x. (Functor s, Monad m, Monad m') => (forall y. m y > m' y) > Coroutine s m x > Coroutine s m' x
 mapSuspension :: forall s s' m x. (Functor s, Monad m) => (forall y. s y > s' y) > Coroutine s m x > Coroutine s' m x
 data Naught x
 runCoroutine :: Monad m => Coroutine Naught m x > m x
 bounce :: (Monad m, Functor s) => (s (Coroutine s m x) > Coroutine s m x) > Coroutine s m x > Coroutine s m x
 pogoStick :: Monad m => (s (Coroutine s m x) > Coroutine s m x) > Coroutine s m x > m x
 foldRun :: Monad m => (a > s (Coroutine s m x) > (a, Coroutine s m x)) > a > Coroutine s m x > m (a, x)
 seesaw :: (Monad m, Functor s1, Functor s2) => PairBinder m > SeesawResolver s1 s2 s1 s2 > Coroutine s1 m x > Coroutine s2 m y > m (x, y)
 data SeesawResolver s1 s2 s1' s2' = SeesawResolver {
 resumeLeft :: forall m t. Monad m => s1 (Coroutine s1' m t) > Coroutine s1' m t
 resumeRight :: forall m t. Monad m => s2 (Coroutine s2' m t) > Coroutine s2' m t
 resumeBoth :: forall m t1 t2 r. Monad m => (Coroutine s1' m t1 > Coroutine s2' m t2 > r) > s1 (Coroutine s1' m t1) > s2 (Coroutine s2' m t2) > r
 seesawSteps :: (Monad m, Functor s1, Functor s2) => PairBinder m > ((Coroutine s1 m x > Coroutine s2 m y > m (x, y)) > CoroutineStepResult s1 m x > CoroutineStepResult s2 m y > m (x, y)) > Coroutine s1 m x > Coroutine s2 m y > m (x, y)
 type PairBinder m = forall x y r. (x > y > m r) > m x > m y > m r
 sequentialBinder :: Monad m => PairBinder m
 parallelBinder :: MonadParallel m => PairBinder m
 liftBinder :: forall s m. (Functor s, Monad m) => PairBinder m > PairBinder (Coroutine s m)
 data SomeFunctor l r x
 composePair :: (Functor a, Functor b) => a x > b y > Compose a b (x, y)
 couple :: forall s1 s2 m x y. (Monad m, Functor s1, Functor s2) => PairBinder m > Coroutine s1 m x > Coroutine s2 m y > Coroutine (SomeFunctor s1 s2) m (x, y)
 merge :: forall s m x. (Monad m, Functor s) => (forall y. [m y] > m [y]) > (forall y. [s y] > s [y]) > [Coroutine s m x] > Coroutine s m [x]
Coroutine definition
newtype Coroutine s m r Source
Suspending, resumable monadic computations.
Functor s => MonadTrans (Coroutine s)  
(Functor s, Monad m) => Monad (Coroutine s m)  
(Functor s, MonadParallel m) => MonadParallel (Coroutine s m)  
(Functor s, MonadIO m) => MonadIO (Coroutine s m) 
type CoroutineStepResult s m r = Either (s (Coroutine s m r)) rSource
suspend :: (Monad m, Functor s) => s (Coroutine s m x) > Coroutine s m xSource
Suspend the current Coroutine
.
Coroutine operations
mapMonad :: forall s m m' x. (Functor s, Monad m, Monad m') => (forall y. m y > m' y) > Coroutine s m x > Coroutine s m' xSource
Change the base monad of a Coroutine
.
mapSuspension :: forall s s' m x. (Functor s, Monad m) => (forall y. s y > s' y) > Coroutine s m x > Coroutine s' m xSource
Change the suspension functor of a Coroutine
.
Running Coroutine computations
The Naught
functor instance doesn't contain anything and cannot be constructed. Used for building nonsuspendable
coroutines.
runCoroutine :: Monad m => Coroutine Naught m x > m xSource
Convert a nonsuspending Coroutine
to the base monad.
bounce :: (Monad m, Functor s) => (s (Coroutine s m x) > Coroutine s m x) > Coroutine s m x > Coroutine s m xSource
Runs a single step of a suspendable Coroutine
, using a function that extracts the coroutine resumption from its
suspension functor.
pogoStick :: Monad m => (s (Coroutine s m x) > Coroutine s m x) > Coroutine s m x > m xSource
Runs a suspendable Coroutine
to its completion.
foldRun :: Monad m => (a > s (Coroutine s m x) > (a, Coroutine s m x)) > a > Coroutine s m x > m (a, x)Source
Runs a suspendable coroutine much like pogoStick
, but allows the resumption function to thread an arbitrary
state as well.
seesaw :: (Monad m, Functor s1, Functor s2) => PairBinder m > SeesawResolver s1 s2 s1 s2 > Coroutine s1 m x > Coroutine s2 m y > m (x, y)Source
Runs two coroutines concurrently. The first argument is used to run the next step of each coroutine, the next to convert the left, right, or both suspensions into the corresponding resumptions.
data SeesawResolver s1 s2 s1' s2' Source
A simple record containing the resolver functions for all possible coroutine pair suspensions.
SeesawResolver  

seesawSteps :: (Monad m, Functor s1, Functor s2) => PairBinder m > ((Coroutine s1 m x > Coroutine s2 m y > m (x, y)) > CoroutineStepResult s1 m x > CoroutineStepResult s2 m y > m (x, y)) > Coroutine s1 m x > Coroutine s2 m y > m (x, y)Source
Runs two coroutines concurrently. The first argument is used to run the next step of each coroutine, the next to convert their step results into the corresponding resumptions.
Coupled Coroutine computations
type PairBinder m = forall x y r. (x > y > m r) > m x > m y > m rSource
Type of functions that can bind two monadic values together; used to combine two coroutines' step results.
sequentialBinder :: Monad m => PairBinder mSource
A PairBinder
that runs the two steps sequentially before combining their results.
parallelBinder :: MonadParallel m => PairBinder mSource
A PairBinder
that runs the two steps in parallel.
liftBinder :: forall s m. (Functor s, Monad m) => PairBinder m > PairBinder (Coroutine s m)Source
Lifting a PairBinder
onto a Coroutine
monad transformer.
data SomeFunctor l r x Source
Combines two functors into one, applying either or both of them. Used for coupled coroutines.
(Functor l, Functor r) => Functor (SomeFunctor l r) 
composePair :: (Functor a, Functor b) => a x > b y > Compose a b (x, y)Source
Combines two values under two functors into a pair of values under a single Compose
.
couple :: forall s1 s2 m x y. (Monad m, Functor s1, Functor s2) => PairBinder m > Coroutine s1 m x > Coroutine s2 m y > Coroutine (SomeFunctor s1 s2) m (x, y)Source
Weaves two coroutines into one. The two coroutines suspend and resume in lockstep. The combined coroutine suspends as long as either argument coroutine suspends, and it completes execution when both arguments do.