conduino-0.2.0.0: Lightweight composable continuation-based stream processors

Copyright(c) Justin Le 2019
LicenseBSD3
Maintainerjustin@jle.im
Stabilityexperimental
Portabilitynon-portable
Safe HaskellNone
LanguageHaskell2010

Data.Conduino.Internal

Description

Internal module exposing the internals of Pipe, including its underlying representation and base functor.

Synopsis

Documentation

newtype Pipe i o u m a Source #

Similar to a conduit from the conduit package.

For a Pipe i o u m a, you have:

  • i: Type of input stream (the things you can await)
  • o: Type of output stream (the things you yield)
  • u: Type of the result of the upstream pipe (Outputted when upstream pipe terminates)
  • m: Underlying monad (the things you can lift)
  • a: Result type when pipe terminates (outputted when finished, with pure or return)

Some specializations:

  • If i is (), the pipe is a source --- it doesn't need anything to produce items. It will pump out items on its own, for pipes downstream to receive and process.
  • If o is Void, the pipe is a sink --- it will never yield anything downstream. It will consume items from things upstream, and produce a result (a) if and when it terminates.
  • If u is Void, then the pipe's upstream is limitless, and never terminates. This means that you can use awaitSurely instead of await, to get await a value that is guaranteed to come. You'll get an i instead of a Maybe i.
  • If a is Void, then the pipe never terminates --- it will keep on consuming and/or producing values forever. If this is a sink, it means that the sink will never terminate, and so runPipe will also never terminate. If it is a source, it means that if you chain something downstream with .|, that downstream pipe can use awaitSurely to guarantee something being passed down.

Applicative and Monadic sequencing of pipes chains by exhaustion.

do pipeX
   pipeY
   pipeZ

is a pipe itself, that behaves like pipeX until it terminates, then pipeY until it terminates, then pipeZ until it terminates. The Monad instance allows you to choose "which pipe to behave like next" based on the terminating result of a previous pipe.

do x <- pipeX
   pipeBasedOn x

Usually you would use it by chaining together pipes with .| and then running the result with runPipe.

runPipe $ someSource
       .| somePipe
       .| someOtherPipe
       .| someSink

See .| and runPipe for more information on usage.

For a "prelude" of commonly used Pipes, see Data.Condunio.Combinators.

Constructors

Pipe 

Fields

Instances
(MonadReader r m, MonadWriter w m, MonadState s m) => MonadRWS r w s (Pipe i o u m) Source # 
Instance details

Defined in Data.Conduino.Internal

MonadWriter w m => MonadWriter w (Pipe i o u m) Source # 
Instance details

Defined in Data.Conduino.Internal

Methods

writer :: (a, w) -> Pipe i o u m a #

tell :: w -> Pipe i o u m () #

listen :: Pipe i o u m a -> Pipe i o u m (a, w) #

pass :: Pipe i o u m (a, w -> w) -> Pipe i o u m a #

MonadState s m => MonadState s (Pipe i o u m) Source # 
Instance details

Defined in Data.Conduino.Internal

Methods

get :: Pipe i o u m s #

put :: s -> Pipe i o u m () #

state :: (s -> (a, s)) -> Pipe i o u m a #

MonadReader r m => MonadReader r (Pipe i o u m) Source # 
Instance details

Defined in Data.Conduino.Internal

Methods

ask :: Pipe i o u m r #

local :: (r -> r) -> Pipe i o u m a -> Pipe i o u m a #

reader :: (r -> a) -> Pipe i o u m a #

MonadError e m => MonadError e (Pipe i o u m) Source # 
Instance details

Defined in Data.Conduino.Internal

Methods

throwError :: e -> Pipe i o u m a #

catchError :: Pipe i o u m a -> (e -> Pipe i o u m a) -> Pipe i o u m a #

MonadTrans (Pipe i o u) Source # 
Instance details

Defined in Data.Conduino.Internal

Methods

lift :: Monad m => m a -> Pipe i o u m a #

MonadFree (PipeF i o u) (Pipe i o u m) Source # 
Instance details

Defined in Data.Conduino.Internal

Methods

wrap :: PipeF i o u (Pipe i o u m a) -> Pipe i o u m a #

Monad (Pipe i o u m) Source # 
Instance details

Defined in Data.Conduino.Internal

Methods

(>>=) :: Pipe i o u m a -> (a -> Pipe i o u m b) -> Pipe i o u m b #

(>>) :: Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m b #

return :: a -> Pipe i o u m a #

fail :: String -> Pipe i o u m a #

Functor (Pipe i o u m) Source # 
Instance details

Defined in Data.Conduino.Internal

Methods

fmap :: (a -> b) -> Pipe i o u m a -> Pipe i o u m b #

(<$) :: a -> Pipe i o u m b -> Pipe i o u m a #

MonadFail m => MonadFail (Pipe i o u m) Source # 
Instance details

Defined in Data.Conduino.Internal

Methods

fail :: String -> Pipe i o u m a #

Applicative (Pipe i o u m) Source # 
Instance details

Defined in Data.Conduino.Internal

Methods

pure :: a -> Pipe i o u m a #

(<*>) :: Pipe i o u m (a -> b) -> Pipe i o u m a -> Pipe i o u m b #

liftA2 :: (a -> b -> c) -> Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m c #

(*>) :: Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m b #

(<*) :: Pipe i o u m a -> Pipe i o u m b -> Pipe i o u m a #

MonadIO m => MonadIO (Pipe i o u m) Source # 
Instance details

Defined in Data.Conduino.Internal

Methods

liftIO :: IO a -> Pipe i o u m a #

data PipeF i o u a Source #

Base functor of Pipe.

A pipe fundamentally has the ability to await and the ability to yield. The other functionality are implemented.

  • Lifting effects is implemented by the MonadTrans and MonadIO instances that FT gives.
  • Ending with a result is implemented by the Applicative instance's pure that FT gives.
  • Applicative and monadic sequenceing "after a pipe is done" is implemented by the Applicative and Monad instances that FT gives.

On top of these we implement .| and other combinators based on the structure that FT gives. For some functions, it can be easier to use an alternative encoding, RecPipe, which is the same thing but explicitly recursive.

Constructors

PAwaitF (u -> a) (i -> a) 
PYieldF o a 
Instances
Functor (PipeF i o u) Source # 
Instance details

Defined in Data.Conduino.Internal

Methods

fmap :: (a -> b) -> PipeF i o u a -> PipeF i o u b #

(<$) :: a -> PipeF i o u b -> PipeF i o u a #

MonadFree (PipeF i o u) (Pipe i o u m) Source # 
Instance details

Defined in Data.Conduino.Internal

Methods

wrap :: PipeF i o u (Pipe i o u m a) -> Pipe i o u m a #

awaitEither :: Pipe i o u m (Either u i) Source #

Await on upstream output. Will block until it receives an i (expected input type) or a u if the upstream pipe terminates.

yield :: o -> Pipe i o u m () Source #

Send output downstream.

trimapPipe :: (i -> j) -> (p -> o) -> (u -> v) -> Pipe j p v m a -> Pipe i o u m a Source #

Map over the input type, output type, and upstream result type.

If you want to map over the result type, use fmap.

mapInput :: (i -> j) -> Pipe j o u m a -> Pipe i o u m a Source #

(Contravariantly) map over the expected input type.

mapOutput :: (p -> o) -> Pipe i p u m a -> Pipe i o u m a Source #

Map over the downstream output type.

If you want to map over the result type, use fmap.

mapUpRes :: (u -> v) -> Pipe i o v m a -> Pipe i o u m a Source #

(Contravariantly) map over the upstream result type.

hoistPipe :: (Monad m, Monad n) => (forall x. m x -> n x) -> Pipe i o u m a -> Pipe i o u n a Source #

Transform the underlying monad of a pipe.

type RecPipe i o u = FreeT (PipeF i o u) Source #

A version of Pipe that uses explicit, concrete recursion instead of church-encoding like Pipe. Some functions --- especially ones that combine multiple pipes into one --- are easier to implement in this form.

toRecPipe :: Monad m => Pipe i o u m a -> RecPipe i o u m a Source #

Convert from a Pipe to a RecPipe. While most of this library is defined in terms of Pipe, it can be easier to write certain low-level pipe combining functions in terms of RecPipe than Pipe.

fromRecPipe :: Monad m => RecPipe i o u m a -> Pipe i o u m a Source #

Convert a RecPipe back into a Pipe.