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. The function seesaw
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 trampoline-style coroutines, see
Trampolined Style - Ganz, S. E. Friedman, D. P. Wand, M, ACM SIGPLAN NOTICES, 1999, VOL 34; NUMBER 9, pages 18-27
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 {}
- 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 x. m x -> m' x) -> Coroutine s m x -> Coroutine s m' x
- mapSuspension :: forall s s' m x. (Functor s, Monad m) => (forall x. s x -> s' x) -> Coroutine s m x -> Coroutine s' m x
- data Naught x
- runCoroutine :: Monad m => Coroutine Naught m x -> 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) => (forall x y r. (x -> y -> m r) -> m x -> m y -> m r) -> SeesawResolver s1 s2 -> Coroutine s1 m x -> Coroutine s2 m y -> m (x, y)
- data SeesawResolver s1 s2 = SeesawResolver {
- resumeLeft :: forall t. s1 t -> t
- resumeRight :: forall t. s2 t -> t
- resumeAny :: forall t1 t2 r. (t1 -> r) -> (t2 -> r) -> (t1 -> t2 -> r) -> s1 t1 -> s2 t2 -> r
- 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 r. (Monad m, Functor s1, Functor s2) => (forall x y r. (x -> y -> m r) -> m x -> m y -> m r) -> 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 x. [m x] -> m [x]) -> (forall x. [s x] -> s [x]) -> [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) |
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 x. m x -> m' x) -> 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 x. s x -> s' x) -> 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 non-suspendable
coroutines.
runCoroutine :: Monad m => Coroutine Naught m x -> m xSource
Convert a non-suspending Coroutine
to the base monad.
pogoStick :: Monad m => (s (Coroutine s m x) -> Coroutine s m x) -> Coroutine s m x -> m xSource
Run a suspendable Coroutine
, using a function that extracts the coroutine resumption from each suspension.
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) => (forall x y r. (x -> y -> m r) -> m x -> m y -> m r) -> SeesawResolver 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 Source
A simple record containing the resolver functions for all possible coroutine pair suspensions.
SeesawResolver | |
|
Coupled Coroutine computations
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
.