quiver 0.0.0.12 → 1.0.0
raw patch · 6 files changed
+340/−63 lines, 6 filesdep +mmorphdep +transformersPVP ok
version bump matches the API change (PVP)
Dependencies added: mmorph, transformers
API changes (from Hackage documentation)
+ Control.Quiver: qhoist :: Functor f => (forall x. f x -> g x) -> P a a' b b' f r -> P a a' b b' g r
+ Control.Quiver.Internal: instance MFunctor (P a a' b b')
+ Control.Quiver.Internal: instance MMonad (P a a' b b')
+ Control.Quiver.Internal: instance MonadIO f => MonadIO (P a a' b b' f)
+ Control.Quiver.Internal: instance MonadTrans (P a a' b b')
+ Control.Quiver.Internal: qembed :: Monad g => (forall x. f x -> P a a' b b' g x) -> P a a' b b' f r -> P a a' b b' g r
+ Control.Quiver.Internal: qhoist :: Functor f => (forall x. f x -> g x) -> P a a' b b' f r -> P a a' b b' g r
+ Control.Quiver.Internal: qlift :: Functor f => f r -> P a a' b b' f r
+ Control.Quiver.SP: (>>?) :: Monad f => P a a' b b' f (SPResult e) -> P a a' b b' f (SPResult e) -> P a a' b b' f (SPResult e)
+ Control.Quiver.SP: spcomplete :: P a a' b b' f (SPResult e)
+ Control.Quiver.SP: spfailed :: e -> P a a' b b' f (SPResult e)
+ Control.Quiver.SP: spincomplete :: P a a' b b' f (SPResult e)
+ Control.Quiver.SP: type SConsumer a f e = forall b. SP a b f e
+ Control.Quiver.SP: type SEffect f e = forall a b. SP a b f e
+ Control.Quiver.SP: type SProducer b f e = forall a. SP a b f e
+ Control.Quiver.Trans: qRunErrorT :: Functor m => P a a' b b' (ErrorT e m) r -> P a a' b b' m (Either e r)
+ Control.Quiver.Trans: qRunExceptT :: Functor m => P a a' b b' (ExceptT e m) r -> P a a' b b' m (Either e r)
+ Control.Quiver.Trans: qRunLazyRWST :: (Functor m, Monoid mw) => P a a' b b' (RWST mr mw ms m) r -> mr -> ms -> P a a' b b' m (r, ms, mw)
+ Control.Quiver.Trans: qRunLazyStateT :: Functor m => P a a' b b' (StateT ms m) r -> ms -> P a a' b b' m (r, ms)
+ Control.Quiver.Trans: qRunLazyWriterT :: (Functor m, Monoid mw) => P a a' b b' (WriterT mw m) r -> P a a' b b' m (r, mw)
+ Control.Quiver.Trans: qRunMaybeT :: Functor m => P a a' b b' (MaybeT m) r -> P a a' b b' m (Maybe r)
+ Control.Quiver.Trans: qRunRWST :: (Functor m, Monoid mw) => P a a' b b' (RWST mr mw ms m) r -> mr -> ms -> P a a' b b' m (r, ms, mw)
+ Control.Quiver.Trans: qRunReaderT :: Functor m => P a a' b b' (ReaderT mr m) r -> mr -> P a a' b b' m r
+ Control.Quiver.Trans: qRunStateT :: Functor m => P a a' b b' (StateT ms m) r -> ms -> P a a' b b' m (r, ms)
+ Control.Quiver.Trans: qRunStrictRWST :: (Functor m, Monoid mw) => P a a' b b' (RWST mr mw ms m) r -> mr -> ms -> P a a' b b' m (r, ms, mw)
+ Control.Quiver.Trans: qRunStrictStateT :: Functor m => P a a' b b' (StateT ms m) r -> ms -> P a a' b b' m (r, ms)
+ Control.Quiver.Trans: qRunStrictWriterT :: (Functor m, Monoid mw) => P a a' b b' (WriterT mw m) r -> P a a' b b' m (r, mw)
+ Control.Quiver.Trans: qRunWriterT :: (Functor m, Monoid mw) => P a a' b b' (WriterT mw m) r -> P a a' b b' m (r, mw)
Files
- README.md +34/−0
- quiver.cabal +36/−38
- src/Control/Quiver.lhs +2/−7
- src/Control/Quiver/Internal.lhs +51/−0
- src/Control/Quiver/SP.lhs +54/−18
- src/Control/Quiver/Trans.lhs +163/−0
+ README.md view
@@ -0,0 +1,34 @@+Quiver+======++ Copyright © 2015 Patryk Zadarnowski «pat@jantar.org».+ All rights reserved.++_Quiver_ is a powerful stream processing library for+combinatorial and monadic representation of computations+over both inductive and coinductive data streams.++It is similar to Gabriel Gonzalez's _pipes_ and+Michael Snoyman's _conduit_, but generalises both+with support for functor-based computations and+a clean support for finite (i.e., inductive) data+streams, both upstream and downstream of the computation+being defined.++The underlying data structure, `P`, is almost identical+to the `Proxy` data structure of the `Pipes` library,+except that the `Consume` and `Produce` constructors+(corresponding, respectively, to `Request` and `Response`+in the Pipes' `Proxy` data type) include an additional+argument which explicitly captures the processor's+behaviour in the event of input stream depletion+(for `Consume`) or output decoupling (for `Produce`).+This simple mechanism subsumes Conduit's need for+elaborate unconsumed-input tracking mechanisms,+and allows us to provide a mathematically-clean+framework for processing of finite data streams.++This library is currently very young, and users should+expect significant changes to the Quiver core combinators+as the underlying theory is developed and the interface+stabilises asymptotically to the future version 1.0.
quiver.cabal view
@@ -1,51 +1,49 @@-name: quiver-version: 0.0.0.12-synopsis: Quiver finite stream processing library-homepage: https://github.com/zadarnowski/quiver-category: Control-stability: alpha--author: Patryk Zadarnowski-maintainer: Patryk Zadarnowski <pat@jantar.org>+name: quiver+version: 1.0.0+synopsis: Quiver finite stream processing library+homepage: https://github.com/zadarnowski/quiver+category: Control+stability: alpha -copyright: Copyright (c) 2015 Patryk Zadarnowski+author: Patryk Zadarnowski+maintainer: Patryk Zadarnowski <pat@jantar.org> -description:+copyright: Copyright (c) 2015 Patryk Zadarnowski - /Quiver/ is a powerful stream processing library for- combinatorial and monadic representation of computations- over both inductive and coinductive data streams.- .- It is similar to Gabriel Gonzalez's /pipes/ and- Michael Snoyman's /conduit/, but generalises both- with support for functor-based computations and- a clean support for finite (i.e., inductive) data- streams, both upstream and downstream of the computation- being defined.+description: /Quiver/ is a powerful stream processing library for+ combinatorial and monadic representation of computations+ over both inductive and coinductive data streams.+ .+ It is similar to Gabriel Gonzalez's /pipes/ and+ Michael Snoyman's /conduit/, but generalises both+ with support for functor-based computations and+ a clean support for finite (i.e., inductive) data+ streams, both upstream and downstream of the computation+ being defined. -cabal-version: >= 1.18-build-type: Simple-license: BSD3-license-file: LICENSE+cabal-version: >= 1.18+build-type: Simple+license: BSD3+license-file: LICENSE+extra-source-files: README.md source-repository head- type: git- location: https://github.com/zadarnowski/quiver.git+ type: git+ location: https://github.com/zadarnowski/quiver.git source-repository this- type: git- location: https://github.com/zadarnowski/quiver.git- tag: 0.0.0.12+ type: git+ location: https://github.com/zadarnowski/quiver.git+ tag: 1.0.0 library hs-source-dirs: src default-language: Haskell2010 ghc-options: -O2 -Wall -fno-warn-unused-do-bind -fno-warn-missing-signatures-- exposed-modules:- Control.Quiver- Control.Quiver.Internal- Control.Quiver.SP-- build-depends:- base >= 4.8 && < 5+ exposed-modules: Control.Quiver+ Control.Quiver.Internal+ Control.Quiver.SP+ Control.Quiver.Trans+ build-depends: base >= 4.8 && < 5,+ mmorph >= 1.0.4,+ transformers >= 0.4.3.0
src/Control/Quiver.lhs view
@@ -19,7 +19,7 @@ > -- Defined below: > fetch, fetch_, > emit, emit_,-> qlift,+> qlift, qhoist, > qpure, qid, qconcat, > runEffect, > (>>->), (>->>), (>&>),@@ -28,7 +28,7 @@ > import Control.Quiver.Internal -> infixl 0 >>->, >->>, >&>+> infixl 1 >>->, >->>, >&> > -- | @fetch x@ represents a singleton stream processor that > -- sends the request value @x@ upstream and delivers the@@ -59,11 +59,6 @@ > emit_ :: b -> P a a' b b' f () > emit_ y = produce y (deliver . const ()) (deliver ())--> -- | @qlift@ lifts the value of a base functor into a stream processor.--> qlift :: Functor f => f r -> P a a' b b' f r-> qlift = enclose . fmap deliver > -- | @qpure g f z@ produces an infinite consumer/producer that > -- uses a pure function @f@ to convert every input value into
src/Control/Quiver/Internal.lhs view
@@ -31,9 +31,13 @@ > P (..), Producer, Consumer, Effect, > consume, produce, enclose, deliver, > decouple, deplete,+> qlift, qhoist, qembed > ) where +> import Control.Monad.IO.Class+> import Control.Monad.Morph + Data Types ========== @@ -143,8 +147,21 @@ > (Produce y k q) >>= kk = Produce y ((>>= kk) . k) (q >>= deplete . kk) > (Enclose f) >>= kk = Enclose (fmap (>>= kk) f) > (Deliver r) >>= kk = kk r+> fail = Enclose . fail +> instance MonadTrans (P a a' b b') where+> lift = qlift +> instance MonadIO f => MonadIO (P a a' b b' f) where+> liftIO = lift . liftIO++> instance MFunctor (P a a' b b') where+> hoist = qhoist++> instance MMonad (P a a' b b') where+> embed = qembed++ Primitive Combinators ===================== @@ -206,3 +223,37 @@ > deplete (Enclose f) = Enclose (fmap deplete f) > deplete (Deliver r) = Deliver r ++ Generalized Transformers+ ========================++> -- | @qlift@ lifts the value of a base functor into a stream processor;+> -- same as 'lift' from 'MonadTrans', but relaxing constraint on+> -- the base structure from 'Monad' to 'Functor'.++> qlift :: Functor f => f r -> P a a' b b' f r+> qlift = enclose . fmap deliver++> -- | @qhoist@ morphs the value of a base functor into another+> -- functor by applying the supplied functor morphism to every+> -- 'Enclose' step of a stream processor; same as 'hoist' from+> -- 'MFunctor' but relaxing the constraint on the base structure+> -- from 'Monad' to 'Functor'.++> qhoist :: Functor f => (forall x . f x -> g x) -> P a a' b b' f r -> P a a' b b' g r+> qhoist ff = loop+> where+> loop (Consume x k q) = consume x (loop . k) (qhoist ff q)+> loop (Produce y k q) = produce y (loop . k) (qhoist ff q)+> loop (Enclose f) = enclose (ff (fmap loop f))+> loop (Deliver r) = deliver r++> -- | @qembed@ ...++> qembed :: Monad g => (forall x . f x -> P a a' b b' g x) -> P a a' b b' f r -> P a a' b b' g r+> qembed ff = loop+> where+> loop (Consume x k q) = consume x (loop . k) (decouple $ qembed ff q)+> loop (Produce y k q) = produce y (loop . k) (deplete $ qembed ff q)+> loop (Enclose f) = ff f >>= loop+> loop (Deliver r) = deliver r
src/Control/Quiver/SP.lhs view
@@ -15,11 +15,12 @@ > module Control.Quiver.SP ( > module Control.Quiver,-> SQ, SP, SPResult,+> SQ, SP, SProducer, SConsumer, SEffect, SPResult, > pattern SPComplete, > pattern SPFailed, > pattern SPIncomplete,-> spfetch, spemit, (>:>), (>>!),+> spcomplete, spfailed, spincomplete,+> spfetch, spemit, (>:>), (>>?), (>>!), > sppure, spid, spconcat, > spfold, spfold', spfoldl, spfoldl', spfoldr, spfoldr', > sptraverse, sptraverse_,@@ -28,7 +29,7 @@ > import Control.Quiver > infixr 5 >:>-> infixl 1 >>!+> infixl 1 >>?, >>! > -- | A /simple processor step/ with a unit request type and an unspecified > -- response type:@@ -42,22 +43,49 @@ > type SP a b f e = SQ a b f (SPResult e) +> -- | A producer version of a simple processor.++> type SProducer b f e = forall a . SP a b f e++> -- | A consumer version of a simple processor.++> type SConsumer a f e = forall b . SP a b f e++> -- | An effect version of a simple processor.++> type SEffect f e = forall a b . SP a b f e+ > -- | Simple processor result type. > type SPResult e = Maybe (Maybe e) -> -- | Simple processor result value indicating successful processing of the entire input stream.+> -- | ('Just Nothing') Simple processor result value indicating successful processing of the entire input stream. > pattern SPComplete = Just Nothing -> -- | Simple processor result value indicating unsuccessful processing of the input stream.+> -- | ('Just (Just e)') Simple processor result value indicating unsuccessful processing of the input stream. > pattern SPFailed e = Just (Just e) -> -- | Simple processor result value indicating premature termination of the consumer.+> -- | ('Nothing') Simple processor result value indicating premature termination of the consumer. > pattern SPIncomplete = Nothing +> -- | Delivers an 'SPComplete' result.++> spcomplete :: P a a' b b' f (SPResult e)+> spcomplete = deliver SPComplete++> -- | Delivers an 'SPFailed' result.++> spfailed :: e -> P a a' b b' f (SPResult e)+> spfailed = deliver . SPFailed++> -- | Delivers an 'SPIncomplete' result.++> spincomplete :: P a a' b b' f (SPResult e)+> spincomplete = deliver SPIncomplete+ > -- | @spfetch@ represents a singleton simple stream processor that > -- sends the request value @x@ upstream and delivers the > -- next input value received, or @Nothing@ if the upstream@@ -72,7 +100,7 @@ > -- or 'SPIncomplete' otherwise. > spemit :: b -> P a a' b b' f (SPResult e)-> spemit y = produce y (const $ deliver SPComplete) (deliver SPIncomplete)+> spemit y = produce y (const spcomplete) spincomplete > -- | @y >:> p@ represents a singleton stream processor that > -- produces a single output value @y@ and continues with@@ -80,16 +108,24 @@ > -- not be consumed by the downstream processor. > (>:>) :: b -> P a a' b b' f (SPResult e) -> P a a' b b' f (SPResult e)-> y >:> p = produce y (const p) (deliver SPIncomplete)+> y >:> p = produce y (const p) spincomplete +> -- | @p >>? q@ continues processing of @p@ with @q@ but only+> -- if @p@ completes successsfully by delivering 'SPComplete',+> -- short-circuiting @q@ if @p@ fails with 'SPIncomplete' or+> -- 'SPFailed'.++> (>>?) :: Monad f => P a a' b b' f (SPResult e) -> P a a' b b' f (SPResult e) -> P a a' b b' f (SPResult e)+> p >>? q = p >>= maybe spincomplete (maybe q spfailed)+ > -- | @p >>! k@ is equivalent to @p@, with any failures in @p@ > -- supplied to the continuation processor @k@. Note that > -- @k@ is not executed if @p@ completes successfully with > -- 'SPComplete' or is interrupted by the downstream processor,-> -- deliverying 'SPIncomplete'.+> -- delivering 'SPIncomplete'. > (>>!) :: Monad f => P a a' b b' f (SPResult e) -> (e -> P a a' b b' f (SPResult e')) -> P a a' b b' f (SPResult e')-> p >>! k = p >>= maybe (deliver SPIncomplete) (maybe (deliver SPComplete) k)+> p >>! k = p >>= maybe spincomplete (maybe spcomplete k) > -- | @sppure f@ produces an infinite consumer/producer that > -- uses a pure function @f@ to convert every input value into@@ -98,24 +134,24 @@ > sppure :: (a -> b) -> SP a b f e > sppure f = cloop > where-> cloop = consume () ploop (deliver SPComplete)-> ploop x = produce (f x) (const cloop) (deliver SPIncomplete)+> cloop = consume () ploop spcomplete+> ploop x = produce (f x) (const cloop) spincomplete > -- | A simple identity processor, equivalent to 'sppure id'. > spid :: SP a a f e > spid = cloop > where-> cloop = consume () ploop (deliver SPComplete)-> ploop x = produce x (const cloop) (deliver SPIncomplete)+> cloop = consume () ploop spcomplete+> ploop x = produce x (const cloop) spincomplete > -- | A simple list flattening processor requests. > spconcat :: SP [a] a f e > spconcat = cloop > where-> cloop = consume () ploop (deliver SPComplete)-> ploop (x:xs) = produce x (const $ ploop xs) (deliver SPIncomplete)+> cloop = consume () ploop spcomplete+> ploop (x:xs) = produce x (const $ ploop xs) spincomplete > ploop [] = cloop > -- | A processor that delivers the entire input of the stream folded@@ -176,7 +212,7 @@ > sptraverse :: Monad m => (a -> m b) -> SP a b m e > sptraverse k = loop > where-> loop = consume () loop' (deliver SPComplete)+> loop = consume () loop' spcomplete > loop' x = qlift (k x) >>= (>:> loop) > -- | A processor that consumes every input elemnet using a monadic function.@@ -184,5 +220,5 @@ > sptraverse_ :: Monad m => (a -> m ()) -> SP a b m e > sptraverse_ k = loop > where-> loop = consume () loop' (deliver SPComplete)+> loop = consume () loop' spcomplete > loop' x = qlift (k x) >> loop
+ src/Control/Quiver/Trans.lhs view
@@ -0,0 +1,163 @@+> -- | Module: Control.Quiver.Trans+> -- Description: Monad transformers for quiver processors+> -- Copyright: © 2015 Patryk Zadarnowski <pat@jantar.org>+> -- License: BSD3+> -- Maintainer: pat@jantar.org+> -- Stability: experimental+> -- Portability: portable+> --+> -- This module provides functions for hoisting stream processors+> -- over the various well-known monad transformers into the corresponding+> -- base monad, in a manner analogous to the tranformers' @run@ function.+> --+> -- This is particularly useful for composing quiver processors over+> -- distinct “compatible” monads such as 'ReaderT' and 'StateT'.++> {-# LANGUAGE RankNTypes #-}+> {-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}++> module Control.Quiver.Trans (+> qRunErrorT,+> qRunExceptT,+> qRunMaybeT,+> qRunRWST, qRunLazyRWST, qRunStrictRWST,+> qRunReaderT,+> qRunStateT, qRunLazyStateT, qRunStrictStateT,+> qRunWriterT, qRunLazyWriterT, qRunStrictWriterT,+> ) where++> import Control.Monad.Trans.Error+> import Control.Monad.Trans.Except+> import Control.Monad.Trans.Maybe+> import Control.Monad.Trans.RWS.Lazy as Lazy+> import Control.Monad.Trans.RWS.Strict as Strict+> import Control.Monad.Trans.Reader+> import Control.Monad.Trans.State.Lazy as Lazy+> import Control.Monad.Trans.State.Strict as Strict+> import Control.Monad.Trans.Writer.Lazy as Lazy+> import Control.Monad.Trans.Writer.Strict as Strict+> import Control.Quiver.Internal++> -- | Hoists a stream processor from an 'ErrorT e m' monad into its base monad @m@.++> qRunErrorT :: Functor m => P a a' b b' (ErrorT e m) r -> P a a' b b' m (Either e r)+> qRunErrorT = loop+> where+> loop (Consume x k q) = consume x (loop . k) (qRunErrorT q)+> loop (Produce y k q) = produce y (loop . k) (qRunErrorT q)+> loop (Enclose f) = enclose (either (deliver . Left) loop <$> runErrorT f)+> loop (Deliver r) = deliver (Right r)++> -- | Hoists a stream processor from an 'ExceptT e m' monad into its base monad @m@.++> qRunExceptT :: Functor m => P a a' b b' (ExceptT e m) r -> P a a' b b' m (Either e r)+> qRunExceptT = loop+> where+> loop (Consume x k q) = consume x (loop . k) (qRunExceptT q)+> loop (Produce y k q) = produce y (loop . k) (qRunExceptT q)+> loop (Enclose f) = enclose (either (deliver . Left) loop <$> runExceptT f)+> loop (Deliver r) = deliver (Right r)++> -- | Hoists a stream processor from a 'MaybeT m' monad into its base monad @m@.++> qRunMaybeT :: Functor m => P a a' b b' (MaybeT m) r -> P a a' b b' m (Maybe r)+> qRunMaybeT = loop+> where+> loop (Consume x k q) = consume x (loop . k) (qRunMaybeT q)+> loop (Produce y k q) = produce y (loop . k) (qRunMaybeT q)+> loop (Enclose f) = enclose (maybe (deliver Nothing) loop <$> runMaybeT f)+> loop (Deliver r) = deliver (Just r)++> -- | Hoists a stream processor from a lazy 'RWST r w s m' monad into its base monad @m@.++> qRunRWST :: (Functor m, Monoid mw) => P a a' b b' (Lazy.RWST mr mw ms m) r -> mr -> ms -> P a a' b b' m (r, ms, mw)+> qRunRWST = qRunLazyRWST++> -- | Hoists a stream processor from a lazy 'RWST r w s m' monad into its base monad @m@.++> qRunLazyRWST :: (Functor m, Monoid mw) => P a a' b b' (Lazy.RWST mr mw ms m) r -> mr -> ms -> P a a' b b' m (r, ms, mw)+> qRunLazyRWST p mr ms = loop p+> where+> loop (Consume x k q) = consume x (loop . k) (qRunLazyRWST q mr ms)+> loop (Produce y k q) = produce y (loop . k) (qRunLazyRWST q mr ms)+> loop (Enclose f) = enclose (run <$> Lazy.runRWST f mr ms)+> loop (Deliver r) = deliver (r, ms, mempty)+> run ~(p', ms', mw) = adj mw <$> qRunLazyRWST p' mr ms'+> adj mw ~(r, ms', mw') = (r, ms', mappend mw mw')++> -- | Hoists a stream processor from a strict 'RWST r w s m' monad into its base monad @m@.++> qRunStrictRWST :: (Functor m, Monoid mw) => P a a' b b' (Strict.RWST mr mw ms m) r -> mr -> ms -> P a a' b b' m (r, ms, mw)+> qRunStrictRWST p mr ms = loop p+> where+> loop (Consume x k q) = consume x (loop . k) (qRunStrictRWST q mr ms)+> loop (Produce y k q) = produce y (loop . k) (qRunStrictRWST q mr ms)+> loop (Enclose f) = enclose (run <$> Strict.runRWST f mr ms)+> loop (Deliver r) = deliver (r, ms, mempty)+> run (p', ms', mw) = adj mw <$> qRunStrictRWST p' mr ms'+> adj mw (r, ms', mw') = (r, ms', mappend mw mw')++> -- | Hoists a stream processor from a 'ReaderT r m' monad into its base monad @m@.++> qRunReaderT :: Functor m => P a a' b b' (ReaderT mr m) r -> mr -> P a a' b b' m r+> qRunReaderT p mr = loop p+> where+> loop (Consume x k q) = consume x (loop . k) (qRunReaderT q mr)+> loop (Produce y k q) = produce y (loop . k) (qRunReaderT q mr)+> loop (Enclose f) = enclose (loop <$> runReaderT f mr)+> loop (Deliver r) = deliver r++> -- | Hoists a stream processor from a lazy 'StateT s m' monad into its base monad @m@.++> qRunStateT :: Functor m => P a a' b b' (Lazy.StateT ms m) r -> ms -> P a a' b b' m (r, ms)+> qRunStateT = qRunLazyStateT++> -- | Hoists a stream processor from a lazy 'StateT s m' monad into its base monad @m@.++> qRunLazyStateT :: Functor m => P a a' b b' (Lazy.StateT ms m) r -> ms -> P a a' b b' m (r, ms)+> qRunLazyStateT p ms = loop p+> where+> loop (Consume x k q) = consume x (loop . k) (qRunLazyStateT q ms)+> loop (Produce y k q) = produce y (loop . k) (qRunLazyStateT q ms)+> loop (Enclose f) = enclose (run <$> Lazy.runStateT f ms)+> loop (Deliver r) = deliver (r, ms)+> run ~(p', ms') = qRunLazyStateT p' ms'++> -- | Hoists a stream processor from a strict 'StateT s m' monad into its base monad @m@.++> qRunStrictStateT :: Functor m => P a a' b b' (Strict.StateT ms m) r -> ms -> P a a' b b' m (r, ms)+> qRunStrictStateT p ms = loop p+> where+> loop (Consume x k q) = consume x (loop . k) (qRunStrictStateT q ms)+> loop (Produce y k q) = produce y (loop . k) (qRunStrictStateT q ms)+> loop (Enclose f) = enclose (uncurry qRunStrictStateT <$> Strict.runStateT f ms)+> loop (Deliver r) = deliver (r, ms)++> -- | Hoists a stream processor from a lazy 'WriterT w m' monad into its base monad @m@.++> qRunWriterT :: (Functor m, Monoid mw) => P a a' b b' (Lazy.WriterT mw m) r -> P a a' b b' m (r, mw)+> qRunWriterT = qRunLazyWriterT++> -- | Hoists a stream processor from a lazy 'WriterT w m' monad into its base monad @m@.++> qRunLazyWriterT :: (Functor m, Monoid mw) => P a a' b b' (Lazy.WriterT mw m) r -> P a a' b b' m (r, mw)+> qRunLazyWriterT p = loop p+> where+> loop (Consume x k q) = consume x (loop . k) (qRunLazyWriterT q)+> loop (Produce y k q) = produce y (loop . k) (qRunLazyWriterT q)+> loop (Enclose f) = enclose (run <$> Lazy.runWriterT f)+> loop (Deliver r) = deliver (r, mempty)+> run ~(p', mw) = adj mw <$> qRunLazyWriterT p'+> adj mw ~(r, mw') = (r, mappend mw mw')++> -- | Hoists a stream processor from a strict 'WriterT w m' monad into its base monad @m@.++> qRunStrictWriterT :: (Functor m, Monoid mw) => P a a' b b' (Strict.WriterT mw m) r -> P a a' b b' m (r, mw)+> qRunStrictWriterT p = loop p+> where+> loop (Consume x k q) = consume x (loop . k) (qRunStrictWriterT q)+> loop (Produce y k q) = produce y (loop . k) (qRunStrictWriterT q)+> loop (Enclose f) = enclose (run <$> Strict.runWriterT f)+> loop (Deliver r) = deliver (r, mempty)+> run (p', mw) = adj mw <$> qRunStrictWriterT p'+> adj mw (r, mw') = (r, mappend mw mw')