{-# OPTIONS_HADDOCK not-home #-}{-# LANGUAGE FlexibleInstances #-}{-# LANGUAGE CPP #-}{-# LANGUAGE MultiParamTypeClasses #-}{-# LANGUAGE UndecidableInstances #-}{-# LANGUAGE RankNTypes #-}{-# LANGUAGE TupleSections #-}{-# LANGUAGE GeneralizedNewtypeDeriving #-}moduleData.Conduit.Internal(-- * TypesPipe(..),ConduitM(..),Source,Producer,Sink,Consumer,Conduit,ResumableSource(..)-- * Primitives,await,awaitE,awaitForever,yield,yieldOr,leftover-- * Finalization,bracketP,addCleanup-- * Composition,idP,pipe,pipeL,connectResume,runPipe,injectLeftovers,(>+>),(<+<)-- * Generalizing,sourceToPipe,sinkToPipe,conduitToPipe,toProducer,toConsumer-- * Utilities,transPipe,mapOutput,mapOutputMaybe,mapInput,sourceList,withUpstream,unwrapResumable)whereimportControl.Applicative(Applicative(..))importControl.Monad((>=>),liftM,ap,when)importControl.Monad.Error.Class(MonadError(..))importControl.Monad.Reader.Class(MonadReader(..))importControl.Monad.RWS.Class(MonadRWS())importControl.Monad.Writer.Class(MonadWriter(..))importControl.Monad.State.Class(MonadState(..))importControl.Monad.Trans.Class(MonadTrans(lift))importControl.Monad.IO.Class(MonadIO(liftIO))importControl.Monad.Base(MonadBase(liftBase))importData.Void(Void,absurd)importData.Monoid(Monoid(mappend,mempty))importControl.Monad.Trans.ResourceimportqualifiedGHC.ExtsimportqualifiedData.IORefasIimportControl.Monad.Morph(MFunctor(..))-- | The underlying datatype for all the types in this package. In has six-- type parameters:---- * /l/ is the type of values that may be left over from this @Pipe@. A @Pipe@-- with no leftovers would use @Void@ here, and one with leftovers would use-- the same type as the /i/ parameter. Leftovers are automatically provided to-- the next @Pipe@ in the monadic chain.---- * /i/ is the type of values for this @Pipe@'s input stream.---- * /o/ is the type of values for this @Pipe@'s output stream.---- * /u/ is the result type from the upstream @Pipe@.---- * /m/ is the underlying monad.---- * /r/ is the result type.---- A basic intuition is that every @Pipe@ produces a stream of output values-- (/o/), and eventually indicates that this stream is terminated by sending a-- result (/r/). On the receiving end of a @Pipe@, these become the /i/ and /u/-- parameters.---- Since 0.5.0dataPipelioumr=-- | Provide new output to be sent downstream. This constructor has three-- fields: the next @Pipe@ to be used, a finalization function, and the-- output value.HaveOutput(Pipelioumr)(m())o-- | Request more input from upstream. The first field takes a new input-- value and provides a new @Pipe@. The second takes an upstream result-- value, which indicates that upstream is producing no more results.|NeedInput(i->Pipelioumr)(u->Pipelioumr)-- | Processing with this @Pipe@ is complete, providing the final result.|Doner-- | Require running of a monadic action to get the next @Pipe@.|PipeM(m(Pipelioumr))-- | Return leftover input, which should be provided to future operations.|Leftover(Pipelioumr)linstanceMonadm=>Functor(Pipelioum)wherefmap=liftMinstanceMonadm=>Applicative(Pipelioum)wherepure=return(<*>)=apinstanceMonadm=>Monad(Pipelioum)wherereturn=DoneHaveOutputpco>>=fp=HaveOutput(p>>=fp)coNeedInputpc>>=fp=NeedInput(p>=>fp)(c>=>fp)Donex>>=fp=fpxPipeMmp>>=fp=PipeM((>>=fp)`liftM`mp)Leftoverpi>>=fp=Leftover(p>>=fp)iinstanceMonadBasebasem=>MonadBasebase(Pipelioum)whereliftBase=lift.liftBaseinstanceMonadTrans(Pipeliou)whereliftmr=PipeM(Done`liftM`mr)instanceMonadIOm=>MonadIO(Pipelioum)whereliftIO=lift.liftIOinstanceMonadThrowm=>MonadThrow(Pipelioum)wheremonadThrow=lift.monadThrowinstanceMonadActivem=>MonadActive(Pipelioum)wheremonadActive=liftmonadActiveinstanceMonadm=>Monoid(Pipelioum())wheremempty=return()mappend=(>>)instanceMonadResourcem=>MonadResource(Pipelioum)whereliftResourceT=lift.liftResourceTinstanceMonadReaderrm=>MonadReaderr(Pipelioum)whereask=liftasklocalf(HaveOutputpco)=HaveOutput(localfp)colocalf(NeedInputpc)=NeedInput(\i->localf(pi))(\u->localf(cu))local_(Donex)=Donexlocalf(PipeMmp)=PipeM(localfmp)localf(Leftoverpi)=Leftover(localfp)i-- Provided for doctest#ifndef MIN_VERSION_mtl#define MIN_VERSION_mtl(x, y, z) 0#endifinstanceMonadWriterwm=>MonadWriterw(Pipelioum)where#if MIN_VERSION_mtl(2, 1, 0)writer=lift.writer#endiftell=lift.telllisten(HaveOutputpco)=HaveOutput(listenp)colisten(NeedInputpc)=NeedInput(\i->listen(pi))(\u->listen(cu))listen(Donex)=Done(x,mempty)listen(PipeMmp)=PipeM$do(p,w)<-listenmpreturn$do(x,w')<-listenpreturn(x,w`mappend`w')listen(Leftoverpi)=Leftover(listenp)ipass(HaveOutputpco)=HaveOutput(passp)copass(NeedInputpc)=NeedInput(\i->pass(pi))(\u->pass(cu))pass(PipeMmp)=PipeM$mp>>=(return.pass)pass(Done(x,_))=Donexpass(Leftoverpi)=Leftover(passp)iinstanceMonadStatesm=>MonadStates(Pipelioum)whereget=liftgetput=lift.put#if MIN_VERSION_mtl(2, 1, 0)state=lift.state#endifinstanceMonadRWSrwsm=>MonadRWSrws(Pipelioum)instanceMonadErrorem=>MonadErrore(Pipelioum)wherethrowError=lift.throwErrorcatchError(HaveOutputpco)f=HaveOutput(catchErrorpf)cocatchError(NeedInputpc)f=NeedInput(\i->catchError(pi)f)(\u->catchError(cu)f)catchError(Donex)_=DonexcatchError(PipeMmp)f=PipeM$catchError(liftM(flipcatchErrorf)mp)(\e->return(fe))catchError(Leftoverpi)f=Leftover(catchErrorpf)i-- | Core datatype of the conduit package. This type represents a general-- component which can consume a stream of input values @i@, produce a stream-- of output values @o@, perform actions in the @m@ monad, and produce a final-- result @r@. The type synonyms provided here are simply wrappers around this-- type.---- Since 1.0.0newtypeConduitMiomr=ConduitM{unConduitM::Pipeiio()mr}deriving(Functor,Applicative,Monad,MonadIO,MonadTrans,MonadThrow,MonadActive,MonadResource,MFunctor)instanceMonadReaderrm=>MonadReaderr(ConduitMiom)whereask=ConduitMasklocalf(ConduitMm)=ConduitM(localfm)instanceMonadWriterwm=>MonadWriterw(ConduitMiom)where#if MIN_VERSION_mtl(2, 1, 0)writer=ConduitM.writer#endiftell=ConduitM.telllisten(ConduitMm)=ConduitM(listenm)pass(ConduitMm)=ConduitM(passm)instanceMonadStatesm=>MonadStates(ConduitMiom)whereget=ConduitMgetput=ConduitM.put#if MIN_VERSION_mtl(2, 1, 0)state=ConduitM.state#endifinstanceMonadRWSrwsm=>MonadRWSrws(ConduitMiom)instanceMonadErrorem=>MonadErrore(ConduitMiom)wherethrowError=ConduitM.throwErrorcatchError(ConduitMm)f=ConduitM$catchErrorm(unConduitM.f)instanceMonadBasebasem=>MonadBasebase(ConduitMiom)whereliftBase=lift.liftBaseinstanceMonadm=>Monoid(ConduitMiom())wheremempty=return()mappend=(>>)-- | Provides a stream of output values, without consuming any input or-- producing a final result.---- Since 0.5.0typeSourcemo=ConduitM()om()-- | A component which produces a stream of output values, regardless of the-- input stream. A @Producer@ is a generalization of a @Source@, and can be-- used as either a @Source@ or a @Conduit@.---- Since 1.0.0typeProducermo=foralli.ConduitMiom()-- | Consumes a stream of input values and produces a final result, without-- producing any output.---- > type Sink i m r = ConduitM i Void m r---- Since 0.5.0typeSinki=ConduitMiVoid-- | A component which consumes a stream of input values and produces a final-- result, regardless of the output stream. A @Consumer@ is a generalization of-- a @Sink@, and can be used as either a @Sink@ or a @Conduit@.---- Since 1.0.0typeConsumerimr=forallo.ConduitMiomr-- | Consumes a stream of input values and produces a stream of output values,-- without producing a final result.---- Since 0.5.0typeConduitimo=ConduitMiom()-- | A @Source@ which has been started, but has not yet completed.---- This type contains both the current state of the @Source@, and the finalizer-- to be run to close it.---- Since 0.5.0dataResumableSourcemo=ResumableSource(Sourcemo)(m())-- | Wait for a single input value from upstream.---- Since 0.5.0await::Pipelioum(Maybei)await=NeedInput(Done.Just)(\_->DoneNothing){-# RULES "await >>= maybe" forall x y. await >>= maybe x y = NeedInput y (const x) #-}{-# INLINE [1] await #-}-- | This is similar to @await@, but will return the upstream result value as-- @Left@ if available.---- Since 0.5.0awaitE::Pipelioum(Eitherui)awaitE=NeedInput(Done.Right)(Done.Left){-# RULES "awaitE >>= either" forall x y. awaitE >>= either x y = NeedInput y x #-}{-# INLINE [1] awaitE #-}-- | Wait for input forever, calling the given inner @Pipe@ for each piece of-- new input. Returns the upstream result type.---- Since 0.5.0awaitForever::Monadm=>(i->Pipeliormr')->PipeliormrawaitForeverinner=selfwhereself=awaitE>>=eitherreturn(\i->inneri>>self){-# INLINE [1] awaitForever #-}-- | Send a single output value downstream. If the downstream @Pipe@-- terminates, this @Pipe@ will terminate as well.---- Since 0.5.0yield::Monadm=>o-- ^ output value->Pipelioum()yield=HaveOutput(Done())(return()){-# INLINE [1] yield #-}-- | Similar to @yield@, but additionally takes a finalizer to be run if the-- downstream @Pipe@ terminates.---- Since 0.5.0yieldOr::Monadm=>o->m()-- ^ finalizer->Pipelioum()yieldOrof=HaveOutput(Done())fo{-# INLINE [1] yieldOr #-}{-# RULES
"yield o >> p" forall o (p :: Pipe l i o u m r). yield o >> p = HaveOutput p (return ()) o
; "mapM_ yield" mapM_ yield = sourceList
; "yieldOr o c >> p" forall o c (p :: Pipe l i o u m r). yieldOr o c >> p = HaveOutput p c o #-}-- | Provide a single piece of leftover input to be consumed by the next pipe-- in the current monadic binding.---- /Note/: it is highly encouraged to only return leftover values from input-- already consumed from upstream.---- Since 0.5.0leftover::l->Pipelioum()leftover=Leftover(Done()){-# INLINE [1] leftover #-}{-# RULES "leftover l >> p" forall l (p :: Pipe l i o u m r). leftover l >> p = Leftover p l #-}-- | Perform some allocation and run an inner @Pipe@. Two guarantees are given-- about resource finalization:---- 1. It will be /prompt/. The finalization will be run as early as possible.---- 2. It is exception safe. Due to usage of @resourcet@, the finalization will-- be run in the event of any exceptions.---- Since 0.5.0bracketP::MonadResourcem=>IOa->(a->IO())->(a->Pipelioumr)->PipelioumrbracketPallocfreeinside=PipeMstartwherestart=do(key,seed)<-allocateallocfreereturn$addCleanup(const$releasekey)(insideseed)-- | Add some code to be run when the given @Pipe@ cleans up.---- Since 0.4.1addCleanup::Monadm=>(Bool->m())-- ^ @True@ if @Pipe@ ran to completion, @False@ for early termination.->Pipelioumr->PipelioumraddCleanupcleanup(Doner)=PipeM(cleanupTrue>>return(Doner))addCleanupcleanup(HaveOutputsrcclosex)=HaveOutput(addCleanupcleanupsrc)(cleanupFalse>>close)xaddCleanupcleanup(PipeMmsrc)=PipeM(liftM(addCleanupcleanup)msrc)addCleanupcleanup(NeedInputpc)=NeedInput(addCleanupcleanup.p)(addCleanupcleanup.c)addCleanupcleanup(Leftoverpi)=Leftover(addCleanupcleanupp)i-- | The identity @Pipe@.---- Since 0.5.0idP::Monadm=>PipelaarmridP=NeedInput(HaveOutputidP(return()))Done-- | Compose a left and right pipe together into a complete pipe. The left pipe-- will be automatically closed when the right pipe finishes.---- Since 0.5.0pipe::Monadm=>Pipelabr0mr1->PipeVoidbcr1mr2->Pipelacr0mr2pipe=goRight(return())wheregoRightfinalleftright=caserightofHaveOutputpco->HaveOutput(recursep)(c>>final)oNeedInputrprc->goLeftrprcfinalleftDoner2->PipeM(final>>return(Doner2))PipeMmp->PipeM(liftMrecursemp)Leftover_i->absurdiwhererecurse=goRightfinalleftgoLeftrprcfinalleft=caseleftofHaveOutputleft'final'o->goRightfinal'left'(rpo)NeedInputleft'lc->NeedInput(recurse.left')(recurse.lc)Doner1->goRight(return())(Doner1)(rcr1)PipeMmp->PipeM(liftMrecursemp)Leftoverleft'i->Leftover(recurseleft')iwhererecurse=goLeftrprcfinal-- | Same as 'pipe', but automatically applies 'injectLeftovers' to the right @Pipe@.---- Since 0.5.0pipeL::Monadm=>Pipelabr0mr1->Pipebbcr1mr2->Pipelacr0mr2-- Note: The following should be equivalent to the simpler:---- pipeL l r = l `pipe` injectLeftovers r---- However, this version tested as being significantly more efficient.pipeL=goRight(return())wheregoRightfinalleftright=caserightofHaveOutputpco->HaveOutput(recursep)(c>>final)oNeedInputrprc->goLeftrprcfinalleftDoner2->PipeM(final>>return(Doner2))PipeMmp->PipeM(liftMrecursemp)Leftoverright'i->goRightfinal(HaveOutputleftfinali)right'whererecurse=goRightfinalleftgoLeftrprcfinalleft=caseleftofHaveOutputleft'final'o->goRightfinal'left'(rpo)NeedInputleft'lc->NeedInput(recurse.left')(recurse.lc)Doner1->goRight(return())(Doner1)(rcr1)PipeMmp->PipeM(liftMrecursemp)Leftoverleft'i->Leftover(recurseleft')iwhererecurse=goLeftrprcfinal-- | Connect a @Source@ to a @Sink@ until the latter closes. Returns both the-- most recent state of the @Source@ and the result of the @Sink@.---- We use a @ResumableSource@ to keep track of the most recent finalizer-- provided by the @Source@.---- Since 0.5.0connectResume::Monadm=>ResumableSourcemo->Sinkomr->m(ResumableSourcemo,r)connectResume(ResumableSource(ConduitMleft0)leftFinal0)(ConduitMright0)=goRightleftFinal0left0right0wheregoRightleftFinalleftright=caserightofHaveOutput__o->absurdoNeedInputrprc->goLeftrprcleftFinalleftDoner2->return(ResumableSource(ConduitMleft)leftFinal,r2)PipeMmp->mp>>=goRightleftFinalleftLeftoverpi->goRightleftFinal(HaveOutputleftleftFinali)pgoLeftrprcleftFinalleft=caseleftofHaveOutputleft'leftFinal'o->goRightleftFinal'left'(rpo)NeedInput_lc->recurse(lc())Done()->goRight(return())(Done())(rc())PipeMmp->mp>>=recurseLeftoverp()->recursepwhererecurse=goLeftrprcleftFinal-- | Run a pipeline until processing completes.---- Since 0.5.0runPipe::Monadm=>PipeVoid()Void()mr->mrrunPipe(HaveOutput__o)=absurdorunPipe(NeedInput_c)=runPipe(c())runPipe(Doner)=returnrrunPipe(PipeMmp)=mp>>=runPiperunPipe(Leftover_i)=absurdi-- | Transforms a @Pipe@ that provides leftovers to one which does not,-- allowing it to be composed.---- This function will provide any leftover values within this @Pipe@ to any-- calls to @await@. If there are more leftover values than are demanded, the-- remainder are discarded.---- Since 0.5.0injectLeftovers::Monadm=>Pipeiioumr->PipelioumrinjectLeftovers=go[]wheregols(HaveOutputpco)=HaveOutput(golsp)cogo(l:ls)(NeedInputp_)=gols$plgo[](NeedInputpc)=NeedInput(go[].p)(go[].c)go_(Doner)=Donergols(PipeMmp)=PipeM(liftM(gols)mp)gols(Leftoverpl)=go(l:ls)p-- | Transform the monad that a @Pipe@ lives in.---- Note that the monad transforming function will be run multiple times,-- resulting in unintuitive behavior in some cases. For a fuller treatment,-- please see:---- <https://github.com/snoyberg/conduit/wiki/Dealing-with-monad-transformers>---- This function is just a synonym for 'hoist'.---- Since 0.4.0transPipe::Monadm=>(foralla.ma->na)->Pipelioumr->PipeliounrtransPipef(HaveOutputpco)=HaveOutput(transPipefp)(fc)otransPipef(NeedInputpc)=NeedInput(transPipef.p)(transPipef.c)transPipe_(Doner)=DonertransPipef(PipeMmp)=PipeM(f$liftM(transPipef)$collapsemp)where-- Combine a series of monadic actions into a single action. Since we-- throw away side effects between different actions, an arbitrary break-- between actions will lead to a violation of the monad transformer laws.-- Example available at:---- http://hpaste.org/75520collapsempipe=dopipe'<-mpipecasepipe'ofPipeMmpipe'->collapsempipe'_->returnpipe'transPipef(Leftoverpi)=Leftover(transPipefp)i-- | Apply a function to all the output values of a @Pipe@.---- This mimics the behavior of `fmap` for a `Source` and `Conduit` in pre-0.4-- days.---- Since 0.4.1mapOutput::Monadm=>(o1->o2)->Pipelio1umr->Pipelio2umrmapOutputf(HaveOutputpco)=HaveOutput(mapOutputfp)c(fo)mapOutputf(NeedInputpc)=NeedInput(mapOutputf.p)(mapOutputf.c)mapOutput_(Doner)=DonermapOutputf(PipeMmp)=PipeM(liftM(mapOutputf)mp)mapOutputf(Leftoverpi)=Leftover(mapOutputfp)i-- | Same as 'mapOutput', but use a function that returns @Maybe@ values.---- Since 0.5.0mapOutputMaybe::Monadm=>(o1->Maybeo2)->Pipelio1umr->Pipelio2umrmapOutputMaybef(HaveOutputpco)=maybeid(\o'p'->HaveOutputp'co')(fo)(mapOutputMaybefp)mapOutputMaybef(NeedInputpc)=NeedInput(mapOutputMaybef.p)(mapOutputMaybef.c)mapOutputMaybe_(Doner)=DonermapOutputMaybef(PipeMmp)=PipeM(liftM(mapOutputMaybef)mp)mapOutputMaybef(Leftoverpi)=Leftover(mapOutputMaybefp)i-- | Apply a function to all the input values of a @Pipe@.---- Since 0.5.0mapInput::Monadm=>(i1->i2)-- ^ map initial input to new input->(l2->Maybel1)-- ^ map new leftovers to initial leftovers->Pipel2i2oumr->Pipel1i1oumrmapInputff'(HaveOutputpco)=HaveOutput(mapInputff'p)comapInputff'(NeedInputpc)=NeedInput(mapInputff'.p.f)(mapInputff'.c)mapInput__(Doner)=DonermapInputff'(PipeMmp)=PipeM(liftM(mapInputff')mp)mapInputff'(Leftoverpi)=maybeid(flipLeftover)(f'i)$mapInputff'p-- | Convert a list into a source.---- Since 0.3.0sourceList::Monadm=>[a]->Pipeliaum()sourceList=gowherego[]=Done()go(o:os)=HaveOutput(goos)(return())o{-# INLINE [1] sourceList #-}-- | The equivalent of @GHC.Exts.build@ for @Pipe@.---- Since 0.4.2build::Monadm=>(forallb.(o->b->b)->b->b)->Pipelioum()buildg=g(\op->HaveOutputp(return())o)(return()){-# RULES
"sourceList/build" forall (f :: (forall b. (a -> b -> b) -> b -> b)). sourceList (GHC.Exts.build f) = build f #-}sourceToPipe::Monadm=>Sourcemo->Pipelioum()sourceToPipe=go.unConduitMwherego(HaveOutputpco)=HaveOutput(gop)cogo(NeedInput_c)=go$c()go(Done())=Done()go(PipeMmp)=PipeM(liftMgomp)go(Leftoverp())=gopsinkToPipe::Monadm=>Sinkimr->PipelioumrsinkToPipe=go.injectLeftovers.unConduitMwherego(HaveOutput__o)=absurdogo(NeedInputpc)=NeedInput(go.p)(const$go$c())go(Doner)=Donergo(PipeMmp)=PipeM(liftMgomp)go(Leftover_l)=absurdlconduitToPipe::Monadm=>Conduitimo->Pipelioum()conduitToPipe=go.injectLeftovers.unConduitMwherego(HaveOutputpco)=HaveOutput(gop)cogo(NeedInputpc)=NeedInput(go.p)(const$go$c())go(Done())=Done()go(PipeMmp)=PipeM(liftMgomp)go(Leftover_l)=absurdl-- | Returns a tuple of the upstream and downstream results. Note that this-- will force consumption of the entire input stream.---- Since 0.5.0withUpstream::Monadm=>Pipelioumr->Pipelioum(u,r)withUpstreamdown=down>>=gowheregor=loopwhereloop=awaitE>>=either(\u->return(u,r))(\_->loop)-- | Unwraps a @ResumableSource@ into a @Source@ and a finalizer.---- A @ResumableSource@ represents a @Source@ which has already been run, and-- therefore has a finalizer registered. As a result, if we want to turn it-- into a regular @Source@, we need to ensure that the finalizer will be run-- appropriately. By appropriately, I mean:---- * If a new finalizer is registered, the old one should not be called.---- * If the old one is called, it should not be called again.---- This function returns both a @Source@ and a finalizer which ensures that the-- above two conditions hold. Once you call that finalizer, the @Source@ is-- invalidated and cannot be used.---- Since 0.5.2unwrapResumable::MonadIOm=>ResumableSourcemo->m(Sourcemo,m())unwrapResumable(ResumableSourcesrcfinal)=doref<-liftIO$I.newIORefTrueletfinal'=dox<-liftIO$I.readIORefrefwhenxfinalreturn(liftIO(I.writeIORefrefFalse)>>src,final')infixr9<+<infixl9>+>-- | Fuse together two @Pipe@s, connecting the output from the left to the-- input of the right.---- Notice that the /leftover/ parameter for the @Pipe@s must be @Void@. This-- ensures that there is no accidental data loss of leftovers during fusion. If-- you have a @Pipe@ with leftovers, you must first call 'injectLeftovers'.---- Since 0.5.0(>+>)::Monadm=>Pipelabr0mr1->PipeVoidbcr1mr2->Pipelacr0mr2(>+>)=pipe{-# INLINE (>+>) #-}-- | Same as '>+>', but reverse the order of the arguments.---- Since 0.5.0(<+<)::Monadm=>PipeVoidbcr1mr2->Pipelabr0mr1->Pipelacr0mr2(<+<)=flippipe{-# INLINE (<+<) #-}-- | Generalize a 'Source' to a 'Producer'.---- Since 1.0.0toProducer::Monadm=>Sourcema->ProducermatoProducer=ConduitM.go.unConduitMwherego(HaveOutputpco)=HaveOutput(gop)cogo(NeedInput_c)=go(c())go(Doner)=Donergo(PipeMmp)=PipeM(liftMgomp)go(Leftoverp())=gop-- | Generalize a 'Sink' to a 'Consumer'.---- Since 1.0.0toConsumer::Monadm=>Sinkamb->ConsumerambtoConsumer=ConduitM.go.unConduitMwherego(HaveOutput__o)=absurdogo(NeedInputpc)=NeedInput(go.p)(go.c)go(Doner)=Donergo(PipeMmp)=PipeM(liftMgomp)go(Leftoverpl)=Leftover(gop)l-- | Since 1.0.4instanceMFunctor(Pipeliou)wherehoist=transPipe