-- 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.8 -- | 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 -- suspension value contains the coroutine's resumption wrapped in a -- Functor. 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, extract it -- from the suspension functor and 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 one way to apply -- pogoStick 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. To run two interleaved computations, use -- a WeaveStepper to weave together steps of two different -- coroutines into a single coroutine, which can then be executed by -- pogoStick. -- -- For various uses of trampoline-style coroutines, see -- --
--   Coroutine Pipelines - Mario Blažević, The Monad.Reader issue 19, pages 29-50
--   
-- --
--   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) -- | Type of functions that can bind two monadic values together, used to -- combine two coroutines' step results. The two functions provided here -- are sequentialBinder and parallelBinder. 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) -- | Type of functions that can weave two coroutines into a single -- coroutine. type Weaver s1 s2 s3 m x y z = Coroutine s1 m x -> Coroutine s2 m y -> Coroutine s3 m z -- | Type of functions capable of combining two coroutines' -- CoroutineStepResult values into a third one. Module -- Monad.Coroutine.SuspensionFunctors contains several -- WeaveStepper examples. type WeaveStepper s1 s2 s3 m x y z = Weaver s1 s2 s3 m x y z -> CoroutineStepResult s1 m x -> CoroutineStepResult s2 m y -> Coroutine s3 m z -- | Weaves two coroutines into one, given a PairBinder to run the -- next step of each coroutine and a WeaveStepper to combine the -- results of the steps. weave :: (Monad m, Functor s1, Functor s2, Functor s3) => PairBinder m -> WeaveStepper s1 s2 s3 m x y z -> Weaver s1 s2 s3 m x y z -- | 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 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) -- | A coroutine can choose to launch 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. A simple coroutine suspension -- can be converted to a nested one using functions mapSuspension -- and liftAncestor. To run nested coroutines, use -- pogoStickNested, or weave with a -- NestWeaveStepper. module Control.Monad.Coroutine.Nested -- | 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 -- | Change the suspension functor of a nested Coroutine. mapNestedSuspension :: (Functor s0, Functor s, Monad m) => (forall y. s y -> s' y) -> Coroutine (EitherFunctor s0 s) m x -> Coroutine (EitherFunctor s0 s') m x -- | 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 -- | Type of functions capable of combining two child coroutines' -- CoroutineStepResult values into a parent coroutine. Use with -- the function weave. type NestWeaveStepper s0 s1 s2 m x y z = WeaveStepper (EitherFunctor s0 s1) (EitherFunctor s0 s2) s0 m x y z -- | 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] (Functor a, ChildFunctor d, d' ~ Parent 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) instance [overlap ok] (Functor l, Functor r) => Functor (EitherFunctor l r) -- | 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. A coroutine with this suspension functor provides a value -- with every suspension. data Yield x y Yield :: x -> y -> Yield x y -- | The Await functor instance is equivalent to (->) but more -- descriptive. A coroutine with this suspension functor demands a value -- whenever it suspends, before it can resume its execution. 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 -- | Combines a Yield of a Reader with an Await for a -- ReadingResult. data ReadRequest x z data ReadingResult x py y -- | A part of the result with the reader of more input ResultPart :: py -> (Reader x py y) -> ReadingResult x py y -- | Final result chunk FinalResult :: y -> ReadingResult x py y type Reader x py y = x -> Reading x py y data Reading x py y -- | Final result chunk with the unconsumed portion of the input Final :: x -> y -> Reading x py y -- | A part of the result with the reader of more input and the EOF Advance :: (Reader x py y) -> y -> py -> Reading x py y -- | Reader of more input, plus the result if there isn't any. Deferred :: (Reader x py y) -> y -> Reading x py y -- | 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 ReadRequest and awaiting the -- ReadingResult. requestRead :: (Monad m, Monoid x) => Reader x py y -> Coroutine (ReadRequest x) m (ReadingResult x py 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 -- | Weaves the suspensions of a Yield and an Await coroutine -- together into a plain Identity coroutine. If the Yield -- coroutine terminates first, the Await one is resumed using the -- argument default value. weaveAwaitYield :: Monad m => x -> WeaveStepper (Await x) (Yield x) Identity m r1 r2 (r1, r2) -- | Like weaveAwaitYield, except the Await coroutine expects -- Maybe-wrapped values. After the Yield coroutine -- terminates, the Await coroutine receives only Nothing. weaveAwaitMaybeYield :: Monad m => WeaveStepper (Await (Maybe x)) (Yield x) Identity m r1 r2 (r1, r2) -- | Weaves two complementary Request coroutine suspensions into a -- coroutine yielding both requests. If one coroutine terminates -- before the other, the remaining coroutine is fed the appropriate -- default value argument. weaveRequests :: Monad m => x -> y -> WeaveStepper (Request x y) (Request y x) (Yield (x, y)) m r1 r2 (r1, r2) -- | The consumer coroutine requests input through ReadRequest and -- gets ReadingResult in response. The producer coroutine receives -- the unconsumed portion of its last requested chunk as response. weaveReadWriteRequests :: (Monad m, Monoid x) => WeaveStepper (ReadRequest x) (Request x x) Identity m r1 r2 (r1, r2) -- | Like weaveReadWriteRequests but for nested coroutines. weaveNestedReadWriteRequests :: (Monad m, Functor s, Monoid x) => NestWeaveStepper s (ReadRequest x) (Request x x) m r1 r2 (r1, r2) instance Functor (ReadRequest x) instance Functor (Request x f) instance Functor (Await x) instance Functor (Yield x)