|
Control.Concurrent.Coroutine |
|
|
|
|
Description |
This module defines the Coroutine monad transformer.
A Coroutine monadic computation can suspend its execution at any time, returning to its invoker. The returned
coroutine suspension contains the continuation of the coroutine embedded in a functor. Here is an example of a
coroutine that suspends computation in the IO monad using the functor Yield:
producer = do yield 1
lift (putStrLn "Produced one, next is four.")
yield 4
return "Finished"
A suspended Coroutine computation can be resumed. The easiest way to run a coroutine 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 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 weave together steps of different
coroutines into a single coroutine using the function couple, which can then be executed by pogoStick.
Coroutines can be run from within another coroutine. In this case, the nested coroutines would normally suspend to
their invoker. Another option is to allow a nested coroutine to suspend both itself and its invoker at once. In this
case, the two suspension functors should be grouped into an EitherFunctor. To run nested coroutines of this kind,
use functions pogoStickNested, seesawNested, and coupleNested.
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
|
|
Synopsis |
|
data Coroutine s m r | | suspend :: (Monad m, Functor s) => s (Coroutine s m x) -> Coroutine s m x | | class Monad m => ParallelizableMonad m where | bindM2 :: (a -> b -> m c) -> m a -> m b -> m c |
| | class (Functor a, Functor d) => AncestorFunctor a d | | runCoroutine :: Monad m => Coroutine Naught m x -> m x | | pogoStick :: (Functor s, Monad m) => (s (Coroutine s m x) -> Coroutine s m x) -> Coroutine s m x -> m x | | pogoStickNested :: (Functor s1, Functor s2, Monad m) => (s2 (Coroutine (EitherFunctor s1 s2) m x) -> Coroutine (EitherFunctor s1 s2) m x) -> Coroutine (EitherFunctor s1 s2) m x -> Coroutine s1 m 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) | | seesawNested :: (Monad m, Functor s0, Functor s1, Functor s2) => (forall x y r. (x -> y -> m r) -> m x -> m y -> m r) -> SeesawResolver s1 s2 -> Coroutine (EitherFunctor s0 s1) m x -> Coroutine (EitherFunctor s0 s2) m y -> Coroutine s0 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 Yield x y = Yield x y | | data Await x y = Await !(x -> y) | | data Naught x | | yield :: forall m x. Monad m => x -> Coroutine (Yield x) m () | | await :: forall m x. Monad m => Coroutine (Await x) m x | | nest :: (Functor a, Functor b) => a x -> b y -> NestedFunctor a b (x, y) | | couple :: (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) | | coupleNested :: (Monad m, Functor s0, Functor s1, Functor s2) => (forall x y r. (x -> y -> m r) -> m x -> m y -> m r) -> Coroutine (EitherFunctor s0 s1) m x -> Coroutine (EitherFunctor s0 s2) m y -> Coroutine (EitherFunctor s0 (SomeFunctor s1 s2)) m (x, y) | | local :: forall m l r x. (Functor r, Monad m) => Coroutine r m x -> Coroutine (EitherFunctor l r) m x | | out :: forall m l r x. (Functor l, Monad m) => Coroutine l m x -> Coroutine (EitherFunctor l r) m x | | liftOut :: forall m a d x. (Monad m, Functor a, AncestorFunctor a d) => Coroutine a m x -> Coroutine d m x | | | | newtype NestedFunctor l r x = NestedFunctor (l (r x)) | | |
|
|
|
Coroutine definition
|
|
|
Suspending, resumable monadic computations.
| Instances | |
|
|
|
Suspend the current Coroutine.
|
|
Useful classes
|
|
|
Class of monads that can perform two computations in parallel.
| | Methods | bindM2 :: (a -> b -> m c) -> m a -> m b -> m c | Source |
| Perform two monadic computations in parallel and pass the results.
|
| | Instances | |
|
|
|
Class of functors that can be lifted.
| | Instances | |
|
|
Running Coroutine computations
|
|
|
Convert a non-suspending Coroutine to the base monad.
|
|
|
Run a Coroutine, using a function that converts suspension to the resumption it wraps.
|
|
|
Run a nested Coroutine that can suspend both itself and the current Coroutine.
|
|
|
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.
|
|
|
Like seesaw, but for nested coroutines that are allowed to suspend the current coroutine as well as themselves.
|
|
data SeesawResolver s1 s2 | Source |
|
A simple record containing the resolver functions for all possible coroutine pair suspensions.
| Constructors | SeesawResolver | | resumeLeft :: forall t. s1 t -> t | resolves the left suspension functor into the resumption it contains
| resumeRight :: forall t. s2 t -> t | resolves the right suspension into its resumption
| invoked when both coroutines are suspended, resolves both suspensions or either one
| resumeAny :: forall t1 t2 r. (t1 -> r) -> (t2 -> r) -> (t1 -> t2 -> r) -> s1 t1 -> s2 t2 -> r | |
|
|
|
|
Suspension functors
|
|
|
The Yield functor instance is equivalent to (,) but more descriptive.
| Constructors | | Instances | |
|
|
|
The Await functor instance is equivalent to (->) but more descriptive.
| Constructors | | Instances | |
|
|
|
The Naught functor instance doesn't contain anything and cannot be constructed. Used for building non-suspendable
coroutines.
| Instances | |
|
|
|
Suspend yielding a value.
|
|
|
Suspend until a value is provided.
|
|
Nested and coupled Coroutine computations
|
|
|
Combines two values under two functors into a pair of values under a single NestedFunctor.
|
|
|
Weaves two coroutines into one.
|
|
|
Weaves two nested coroutines into one.
|
|
|
Converts a coroutine into a nested one.
|
|
|
Converts a coroutine into one that can contain nested coroutines.
|
|
|
Like out, working over multiple functors.
|
|
data EitherFunctor l r x | Source |
|
Combines two alternative functors into one, applying one or the other. Used for nested coroutines.
| Constructors | | Instances | |
|
|
newtype NestedFunctor l r x | Source |
|
Combines two functors into one, applying both.
| Constructors | | Instances | |
|
|
|
Combines two functors into one, applying either or both of them. Used for coupled coroutines.
| Constructors | | Instances | |
|
|
Produced by Haddock version 2.6.0 |