scc-0.4: Streaming component combinatorsSource codeContentsIndex
Control.Concurrent.Coroutine
Contents
Coroutine definition
Useful classes
Running Coroutine computations
Suspension functors
Nested and coupled Coroutine computations
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
data EitherFunctor l r x
= LeftF (l x)
| RightF (r x)
newtype NestedFunctor l r x = NestedFunctor (l (r x))
data SomeFunctor l r x
= LeftSome (l x)
| RightSome (r x)
| Both (NestedFunctor l r x)
Coroutine definition
data Coroutine s m r Source
Suspending, resumable monadic computations.
show/hide Instances
suspend :: (Monad m, Functor s) => s (Coroutine s m x) -> Coroutine s m xSource
Suspend the current Coroutine.
Useful classes
class Monad m => ParallelizableMonad m whereSource
Class of monads that can perform two computations in parallel.
Methods
bindM2 :: (a -> b -> m c) -> m a -> m b -> m cSource
Perform two monadic computations in parallel and pass the results.
show/hide Instances
class (Functor a, Functor d) => AncestorFunctor a d Source
Class of functors that can be lifted.
show/hide Instances
Running Coroutine computations
runCoroutine :: Monad m => Coroutine Naught m x -> m xSource
Convert a non-suspending Coroutine to the base monad.
pogoStick :: (Functor s, Monad m) => (s (Coroutine s m x) -> Coroutine s m x) -> Coroutine s m x -> m xSource
Run a Coroutine, using a function that converts suspension to the resumption it wraps.
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 xSource
Run a nested Coroutine that can suspend both itself and the current Coroutine.
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.
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)Source
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 -> tresolves the left suspension functor into the resumption it contains
resumeRight :: forall t. s2 t -> tresolves 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
data Yield x y Source
The Yield functor instance is equivalent to (,) but more descriptive.
Constructors
Yield x y
show/hide Instances
data Await x y Source
The Await functor instance is equivalent to (->) but more descriptive.
Constructors
Await !(x -> y)
show/hide Instances
data Naught x Source
The Naught functor instance doesn't contain anything and cannot be constructed. Used for building non-suspendable coroutines.
show/hide Instances
yield :: forall m x. Monad m => x -> Coroutine (Yield x) m ()Source
Suspend yielding a value.
await :: forall m x. Monad m => Coroutine (Await x) m xSource
Suspend until a value is provided.
Nested and coupled Coroutine computations
nest :: (Functor a, Functor b) => a x -> b y -> NestedFunctor a b (x, y)Source
Combines two values under two functors into a pair of values under a single NestedFunctor.
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)Source
Weaves two coroutines into one.
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)Source
Weaves two nested coroutines into one.
local :: forall m l r x. (Functor r, Monad m) => Coroutine r m x -> Coroutine (EitherFunctor l r) m xSource
Converts a coroutine into a nested one.
out :: forall m l r x. (Functor l, Monad m) => Coroutine l m x -> Coroutine (EitherFunctor l r) m xSource
Converts a coroutine into one that can contain nested coroutines.
liftOut :: forall m a d x. (Monad m, Functor a, AncestorFunctor a d) => Coroutine a m x -> Coroutine d m xSource
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
LeftF (l x)
RightF (r x)
show/hide Instances
newtype NestedFunctor l r x Source
Combines two functors into one, applying both.
Constructors
NestedFunctor (l (r x))
show/hide Instances
data SomeFunctor l r x Source
Combines two functors into one, applying either or both of them. Used for coupled coroutines.
Constructors
LeftSome (l x)
RightSome (r x)
Both (NestedFunctor l r x)
show/hide Instances
Produced by Haddock version 2.6.0