-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Coroutine monad transformer for suspending and resuming monadic computations -- -- This package defines a monad transformer, applicable to any monad, -- that allows the monadic computation to suspend and to be later -- resumed. The transformer is parameterized by an arbitrary functor, -- used to store the suspended computation's resumption. @package monad-coroutine @version 0.7 -- | 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 --module Control.Monad.Coroutine -- | Suspending, resumable monadic computations. newtype Coroutine s m r Coroutine :: m (Either (s (Coroutine s m r)) r) -> Coroutine s m 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. resume :: Coroutine s m r -> m (Either (s (Coroutine s m r)) r) type CoroutineStepResult s m r = Either (s (Coroutine s m r)) r -- | Suspend the current Coroutine. suspend :: (Monad m, Functor s) => s (Coroutine s m x) -> Coroutine s m x -- | Change the base monad of a Coroutine. mapMonad :: (Functor s, Monad m, Monad m') => (forall y. m y -> m' y) -> Coroutine s m x -> Coroutine s m' x -- | Change the suspension functor of a Coroutine. mapSuspension :: (Functor s, Monad m) => (forall y. s y -> s' y) -> Coroutine s m x -> Coroutine s' m x -- | Modify the first upcoming suspension of a Coroutine. mapFirstSuspension :: (Functor s, Monad m) => (forall y. s y -> s y) -> Coroutine s m x -> Coroutine s m x -- | The Naught functor instance doesn't contain anything and cannot -- be constructed. Used for building non-suspendable coroutines. data Naught x -- | Convert a non-suspending Coroutine to the base monad. runCoroutine :: Monad m => Coroutine Naught m x -> m x -- | Runs a single step of a suspendable Coroutine, using a function -- that extracts the coroutine resumption from its suspension functor. bounce :: (Monad m, Functor s) => (s (Coroutine s m x) -> Coroutine s m x) -> Coroutine s m x -> Coroutine s m x -- | Runs a suspendable Coroutine to its completion. pogoStick :: Monad m => (s (Coroutine s m x) -> Coroutine s m x) -> Coroutine s m x -> m x -- | Runs a suspendable coroutine much like pogoStick, but allows -- the resumption function to thread an arbitrary state as well. foldRun :: Monad m => (a -> s (Coroutine s m x) -> (a, Coroutine s m x)) -> a -> Coroutine s m x -> m (a, x) -- | 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. 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) -- | A simple record containing the resolver functions for all possible -- coroutine pair suspensions. data SeesawResolver s1 s2 s1' s2' SeesawResolver :: (forall m t. Monad m => s1 (Coroutine s1' m t) -> Coroutine s1' m t) -> (forall m t. Monad m => s2 (Coroutine s2' m t) -> Coroutine s2' m t) -> (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) -> SeesawResolver s1 s2 s1' s2' -- | resolves the left suspension functor into the resumption it contains resumeLeft :: SeesawResolver s1 s2 s1' s2' -> forall m t. Monad m => s1 (Coroutine s1' m t) -> Coroutine s1' m t -- | resolves the right suspension into its resumption resumeRight :: SeesawResolver s1 s2 s1' s2' -> forall m t. Monad m => s2 (Coroutine s2' m t) -> Coroutine s2' m t -- | invoked when both coroutines are suspended, resolves both suspensions -- or either one resumeBoth :: SeesawResolver s1 s2 s1' s2' -> 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 -- | 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. 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 of functions that can bind two monadic values together; used to -- combine two coroutines' step results. type PairBinder m = forall x y r. (x -> y -> m r) -> m x -> m y -> m r -- | A PairBinder that runs the two steps sequentially before -- combining their results. sequentialBinder :: Monad m => PairBinder m -- | A PairBinder that runs the two steps in parallel. parallelBinder :: MonadParallel m => PairBinder m -- | Lifting a PairBinder onto a Coroutine monad transformer. liftBinder :: (Functor s, Monad m) => PairBinder m -> PairBinder (Coroutine s m) -- | Combines two functors into one, applying either or both of them. Used -- for coupled coroutines. data SomeFunctor l r x LeftSome :: (l x) -> SomeFunctor l r x RightSome :: (r x) -> SomeFunctor l r x Both :: (Compose l r x) -> SomeFunctor l r x -- | Combines two values under two functors into a pair of values under a -- single Compose. composePair :: (Functor a, Functor b) => a x -> b y -> Compose a b (x, y) -- | 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. couple :: (Monad m, Functor s1, Functor s2) => PairBinder m -> Coroutine s1 m x -> Coroutine s2 m y -> Coroutine (SomeFunctor s1 s2) m (x, y) -- | Weaves a list of coroutines with the same suspension functor type into -- a single coroutine. The coroutines suspend and resume in lockstep. merge :: (Monad m, Functor s) => (forall y. [m y] -> m [y]) -> (forall y. [s y] -> s [y]) -> [Coroutine s m x] -> Coroutine s m [x] instance (Functor l, Functor r) => Functor (SomeFunctor l r) instance Functor Naught instance (Functor s, MonadIO m) => MonadIO (Coroutine s m) instance Functor s => MonadTrans (Coroutine s) instance (Functor s, MonadParallel m) => MonadParallel (Coroutine s m) instance (Functor s, Monad m) => Monad (Coroutine s m) instance (Functor s, Functor m, Monad m) => Applicative (Coroutine s m) instance (Functor s, Functor m) => Functor (Coroutine s m) -- | This module defines the Ticker cofunctor, useful for 'ticking off' a -- prefix of the input. module Data.Functor.Contravariant.Ticker -- | This is a contra-functor data type for selecting a prefix of an input -- stream. If the next input item is acceptable, the ticker function -- returns the ticker for the rest of the stream. If not, it returns -- Nothing. newtype Ticker x Ticker :: (x -> Maybe (Ticker x)) -> Ticker x -- | Extracts a list prefix accepted by the Ticker argument. Returns -- the modified ticker, the prefix, and the remainder of the list. splitTicked :: Ticker x -> [x] -> (Ticker x, [x], [x]) -- | Any instance should be subject to the following laws: -- --
-- contramap id = id -- contramap f . contramap g = contramap (g . f) ---- -- Note, that the second law follows from the free theorem of the type of -- contramap and the first law, so you need only check that the -- former condition holds. class Contravariant f :: (* -> *) contramap :: Contravariant f => (a -> b) -> f b -> f a -- | A ticker that accepts no input. tickNone :: Ticker x -- | A ticker that accepts a single input item. tickOne :: Ticker x -- | A ticker that accepts a given number of input items. tickCount :: Int -> Ticker x -- | A ticker that accepts the longest prefix of input that matches a -- prefix of the argument list. tickPrefixOf :: Eq x => [x] -> Ticker x -- | A ticker that accepts a prefix of input as long as each item satisfies -- the predicate at the same position in the argument list. The length of -- the predicate list thus determines the maximum number of acepted -- values. tickWhilePrefixOf :: [x -> Bool] -> Ticker x -- | A ticker that accepts all input as long as it matches the given -- predicate. tickWhile :: (x -> Bool) -> Ticker x -- | A ticker that accepts all input items until one matches the given -- predicate. tickUntil :: (x -> Bool) -> Ticker x -- | A ticker that accepts all input. tickAll :: Ticker x -- | Sequential concatenation ticker combinator: when the first argument -- ticker stops ticking, the second takes over. andThen :: Ticker x -> Ticker x -> Ticker x -- | Parallel conjunction ticker combinator: the result keeps ticking as -- long as both arguments do. and :: Ticker x -> Ticker x -> Ticker x -- | Parallel choice ticker combinator: the result keeps ticking as long as -- any of the arguments does. or :: Ticker x -> Ticker x -> Ticker x instance Contravariant Ticker -- | This module defines some common suspension functors for use with the -- Control.Monad.Coroutine module. module Control.Monad.Coroutine.SuspensionFunctors -- | The Yield functor instance is equivalent to (,) but more -- descriptive. data Yield x y Yield :: x -> y -> Yield x y -- | The Await functor instance is equivalent to (->) but more -- descriptive. newtype Await x y Await :: (x -> y) -> Await x y -- | The Request functor instance combines a Yield of a -- request with an Await for a response. data Request request response x Request :: request -> (response -> x) -> Request request response x data ParseRequest x z -- | Combines two alternative functors into one, applying one or the other. -- Used for nested coroutines. data EitherFunctor l r x LeftF :: (l x) -> EitherFunctor l r x RightF :: (r x) -> EitherFunctor l r x -- | Like either for the EitherFunctor data type. eitherFunctor :: (l x -> y) -> (r x -> y) -> EitherFunctor l r x -> y -- | Suspend the current coroutine yielding a value. yield :: Monad m => x -> Coroutine (Yield x) m () -- | Suspend the current coroutine until a value is provided. await :: Monad m => Coroutine (Await x) m x -- | Suspend yielding a request and awaiting the response. request :: Monad m => x -> Coroutine (Request x y) m y -- | Suspend yielding a request and awaiting the response. requestParse :: (Monad m, MonoidNull y) => Parser [x] y -> Coroutine (ParseRequest x) m (y, Maybe (Parser [x] y)) -- | Converts a coroutine yielding collections of values into one yielding -- single values. concatYields :: (Monad m, Foldable f) => Coroutine (Yield (f x)) m r -> Coroutine (Yield x) m r -- | Converts a coroutine awaiting single values into one awaiting -- collections of values. concatAwaits :: (Monad m, Foldable f) => Coroutine (Await x) m r -> Coroutine (Await (f x)) m r -- | A SeesawResolver for running two coroutines in parallel, one of -- which awaits values while the other yields them. The -- yielding coroutine must not terminate before the other one. awaitYieldResolver :: SeesawResolver (Await x) (Yield x) s1 s2 -- | A SeesawResolver for running two coroutines in parallel, one of -- which awaits values while the other yields them. If the -- yielding coroutine terminates before the awaiting one, the latter will -- receive Nothing. awaitMaybeYieldResolver :: SeesawResolver (Await (Maybe x)) (Yield x) s1 s2 -- | A SeesawResolver for running two coroutines in parallel, one of -- which awaits non-empty lists of values while the other -- yields them. If the yielding coroutine dies, the awaiting -- coroutine receives empty lists. awaitYieldChunkResolver :: SeesawResolver (Await [x]) (Yield [x]) s1 s2 -- | A SeesawResolver for running two requesting coroutines -- in parallel. One coroutine's request becomes the other's response, and -- vice versa. requestsResolver :: SeesawResolver (Request x y) (Request y x) s1 s2 -- | A SeesawResolver for running two coroutines in parallel. One -- coroutine produces data in chunks, the other consumes data in chunks. -- The boundaries of the two kinds of chunks need not be the same, as the -- consumed chunks are determined by a Ticker provided by the -- consumer's input request. tickerYieldResolver :: SeesawResolver (Request (Ticker x) [x]) (Yield [x]) (Request (Ticker x) [x]) (Yield [x]) -- | Like tickerYieldResolver, the only difference being that the -- producing coroutine sends its chunks using request rather than -- yield. The feedback received from request is the -- unconsumed remainder of the chunk, which lets the coroutine know when -- its sibling terminates. tickerRequestResolver :: SeesawResolver (Request (Ticker x) [x]) (Request [x] [x]) (Request (Ticker x) [x]) (Request [x] [x]) -- | Like tickerRequestResolver, except the consuming coroutine -- requests receive both the selected prefix of the input chunk and a -- peek at either the next unconsumed input item, if any, or the final -- Ticker value. Chunks sent by the producing coroutine never get -- combined for the consuming coroutine. This allows better -- synchronization between the two coroutines. It also leaks the -- information about the produced chunk boundaries into the consuming -- coroutine, so this resolver should be used with caution. lazyTickerRequestResolver :: SeesawResolver (Request (Ticker x) ([x], Either x (Ticker x))) (Request [x] [x]) (Request (Ticker x) ([x], Either x (Ticker x))) (Request [x] [x]) -- | Like parserYieldResolver, the only difference being that the -- producing coroutine sends its chunks using request rather than -- yield. The feedback received from request is the -- unconsumed remainder of the chunk, which lets the coroutine know when -- its sibling terminates. parserRequestResolver :: Monoid y => SeesawResolver (Request (Parser [x] y) y) (Request [x] [x]) (Request (Parser [x] y) y) (Request [x] [x]) -- | Like parserRequestResolver, except the consuming coroutine -- requests receive both the selected prefix of the input chunk and a -- peek at either the next unconsumed input item, if any, or the final -- Parser value. Chunks sent by the producing coroutine never get -- combined for the consuming coroutine. This allows better -- synchronization between the two coroutines. It also leaks the -- information about the produced chunk boundaries into the consuming -- coroutine, so this resolver should be used with caution. lazyParserRequestResolver :: SeesawResolver (ParseRequest x) (Request [x] [x]) (ParseRequest x) (Request [x] [x]) -- | A generic version of tickerYieldResolver, allowing coroutines -- with Request and Yield functors embedded in other -- functors. liftedTickerYieldResolver :: (Functor s1, Functor s2) => (forall a. Request (Ticker x) [x] a -> s1 a) -> (forall a. Yield [x] a -> s2 a) -> SeesawResolver (Request (Ticker x) [x]) (Yield [x]) s1 s2 -- | A generic version of tickerRequestResolver, allowing coroutines -- with Request functors embedded in other functors. liftedTickerRequestResolver :: (Functor s1, Functor s2) => (forall a. Request (Ticker x) [x] a -> s1 a) -> (forall a. Request [x] [x] a -> s2 a) -> SeesawResolver (Request (Ticker x) [x]) (Request [x] [x]) s1 s2 -- | A generic version of lazyTickerRequestResolver, allowing -- coroutines with Request functors embedded in other functors. liftedLazyTickerRequestResolver :: (Functor s1, Functor s2) => (forall a. Request [x] [x] a -> s2 a) -> SeesawResolver (Request (Ticker x) ([x], Either x (Ticker x))) (Request [x] [x]) s1 s2 -- | A generic version of parserRequestResolver, allowing coroutines -- with Request functors embedded in other functors. liftedParserRequestResolver :: (Functor s1, Functor s2, Monoid y) => (forall a. Request (Parser [x] y) y a -> s1 a) -> (forall a. Request [x] [x] a -> s2 a) -> SeesawResolver (Request (Parser [x] y) y) (Request [x] [x]) s1 s2 -- | A generic version of lazyParserRequestResolver, allowing -- coroutines with Request functors embedded in other functors. nestedLazyParserRequestResolver :: (Functor s1, Functor s2) => SeesawResolver (ParseRequest x) (Request [x] [x]) (EitherFunctor s1 (ParseRequest x)) (EitherFunctor s2 (Request [x] [x])) instance (Functor l, Functor r) => Functor (EitherFunctor l r) instance Functor (ParseRequest x) instance Functor (Request x f) instance Functor (Await x) instance Functor (Yield x) -- | This module defines nestable suspension functors for use with the -- Coroutine monad transformer, as well as functions for running -- nested coroutines of this sort. -- -- Coroutines can be run from within another coroutine. In this case, the -- nested coroutines always suspend to their invoker. If a function from -- this module, such as pogoStickNested, is used to run a nested -- coroutine, the parent coroutine can be automatically suspended as -- well. A single suspension can thus suspend an entire chain of nested -- coroutines. -- -- Nestable coroutines of this kind should group their suspension -- functors into an EitherFunctor. You can adjust a normal -- suspension, such as the one produced by yield, using -- functions mapSuspension and liftAncestor. To run nested -- coroutines, use functions pogoStickNested, seesawNested, -- and coupleNested. module Control.Monad.Coroutine.Nested -- | Run a nested Coroutine that can suspend both itself and the -- current Coroutine. 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 -- | Much like couple, but with two nested coroutines. coupleNested :: (Monad m, Functor s0, Monad s0, Functor s1, Functor s2) => PairBinder m -> Coroutine (EitherFunctor s0 s1) m x -> Coroutine (EitherFunctor s0 s2) m y -> Coroutine (EitherFunctor s0 (SomeFunctor s1 s2)) m (x, y) -- | Like seesaw, but for nested coroutines that are allowed to -- suspend the current coroutine as well as themselves. If both -- coroutines try to suspend the current coroutine in the same step, the -- left coroutine's suspension will have precedence. seesawNested :: (Monad m, Functor s0, Functor s1, Functor s2) => PairBinder m -> SeesawResolver s1 s2 (EitherFunctor s0 s1) (EitherFunctor s0 s2) -> Coroutine (EitherFunctor s0 s1) m x -> Coroutine (EitherFunctor s0 s2) m y -> Coroutine s0 m (x, y) -- | Like seesawSteps, but for nested coroutines that are allowed to -- suspend the current coroutine as well as themselves. If both -- coroutines try to suspend the current coroutine in the same step, the -- left coroutine's suspension will have precedence. seesawNestedSteps :: (Monad m, Functor s0, Functor s1, Functor s2, s1' ~ (EitherFunctor s0 s1), s2' ~ (EitherFunctor s0 s2), c1 ~ (Coroutine s1' m x), c2 ~ (Coroutine s2' m y)) => PairBinder m -> ((c1 -> c2 -> Coroutine s0 m (x, y)) -> Either (s1 c1) x -> Either (s2 c2) y -> Coroutine s0 m (x, y)) -> c1 -> c2 -> Coroutine s0 m (x, y) -- | Class of functors that can contain another functor. class Functor c => ChildFunctor c where { type family Parent c :: * -> *; } wrap :: ChildFunctor c => Parent c x -> c x -- | Class of functors that can be lifted. class (Functor a, Functor d) => AncestorFunctor a d liftFunctor :: AncestorFunctor a d => a x -> d x -- | Converts a coroutine into a child nested coroutine. liftParent :: (Monad m, Functor p, ChildFunctor c, p ~ (Parent c)) => Coroutine p m x -> Coroutine c m x -- | Converts a coroutine into a descendant nested coroutine. liftAncestor :: (Monad m, Functor a, AncestorFunctor a d) => Coroutine a m x -> Coroutine d m x instance [overlap ok] (d' ~ Parent d, Functor a, ChildFunctor d, AncestorFunctor a d') => AncestorFunctor a d instance [overlap ok] Functor a => AncestorFunctor a a instance [overlap ok] (Functor p, Functor s) => ChildFunctor (EitherFunctor p s)