monad-coroutine-0.7: Coroutine monad transformer for suspending and resuming monadic computations

Control.Monad.Coroutine

Contents

Description

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 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

Coroutine definition

newtype Coroutine s m r Source

Suspending, resumable monadic computations.

Constructors

Coroutine 

Fields

resume :: m (Either (s (Coroutine s m r)) r)

Run the next step of a Coroutine computation. The result of the step execution will be either a suspension or the final coroutine result.

Instances

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 :: (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.

mapFirstSuspension :: forall s s' m x. (Functor s, Monad m) => (forall y. s y -> s y) -> Coroutine s m x -> Coroutine s m xSource

Modify the first upcoming suspension of a Coroutine.

Running Coroutine computations

data Naught x Source

The Naught functor instance doesn't contain anything and cannot be constructed. Used for building non-suspendable coroutines.

Instances

runCoroutine :: Monad m => Coroutine Naught m x -> m xSource

Convert a non-suspending 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.

Constructors

SeesawResolver 

Fields

resumeLeft :: forall m t. Monad m => s1 (Coroutine s1' m t) -> Coroutine s1' m t

resolves the left suspension functor into the resumption it contains

resumeRight :: forall m t. Monad m => s2 (Coroutine s2' m t) -> Coroutine s2' m t

resolves the right suspension into its resumption

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

invoked when both coroutines are suspended, resolves both suspensions or either one

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.

Constructors

LeftSome (l x) 
RightSome (r x) 
Both (Compose l r x) 

Instances

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.

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]Source

Weaves a list of coroutines with the same suspension functor type into a single coroutine. The coroutines suspend and resume in lockstep.