conduino-0.2.3.0: Lightweight composable continuation-based stream processors
Copyright(c) Justin Le 2019
LicenseBSD3
Maintainerjustin@jle.im
Stabilityexperimental
Portabilitynon-portable
Safe HaskellSafe-Inferred
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.Conduino.Combinators.

Constructors

Pipe 

Fields

Instances

Instances details
(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

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 #

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 #

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 #

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 #

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 #

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 #

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 #

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

Defined in Data.Conduino.Internal

Methods

empty :: Pipe i o u m a #

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

some :: Pipe i o u m a -> Pipe i o u m [a] #

many :: Pipe i o u m a -> 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 #

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 #

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 #

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

Defined in Data.Conduino.Internal

Methods

mzero :: Pipe i o u m a #

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

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

Defined in Data.Conduino.Internal

Methods

catch :: Exception e => Pipe i o u m a -> (e -> Pipe i o u m a) -> Pipe i o u m a #

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

Defined in Data.Conduino.Internal

Methods

throwM :: Exception e => e -> 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

Instances details
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.

Since v0.2.3.0, is strict. See yieldLazy for the original behavior.

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

Send output downstream without forcing its argument.

Since: 0.2.3.0

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.

trimapPipeF :: (i -> j) -> (p -> o) -> (u -> v) -> PipeF j p v a -> PipeF i o u a Source #

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.

Note that if you are trying to work with monad transformers, this is probably not what you want. See Data.Conduino.Lift for tools for working with underlying monad transformers.

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.

withRecPipe :: (Monad m, Monad n) => (RecPipe i o u m a -> RecPipe j p v n b) -> Pipe i o u m a -> Pipe j p v n b Source #

Convenint wrapper over toRecPipe and fromRecPipe.

Since: 0.2.1.0

runStateP :: Monad m => s -> Pipe i o u (StateT s m) a -> Pipe i o u m (a, s) Source #

Turn a Pipe that runs over StateT into a "state-modifying Pipe", that returns the final state when it terminates.

The main usage of this is to "isolate" the state from other pipes in the same chain. For example, of p, q, and r are all pipes under StateT, then:

    p
 .| q
 .| r

will all share underlying state, and each can modify the state that they all three share. We essentially have global state.

However, if you use runStateP, you can all have them use different encapsulated states.

    void (runStateP s0 p)
 .| void (runStateP s1 q)
 .| runStateP s2 r

In this case, each of those three chained pipes will use their own internal states, without sharing.

This is also useful if you want to chain a pipe over StateT with pipes that don't use state at all: for example if a and b are "non-stateful" pipes (not over StateT), you can do:

    a
 .| void (runStateP s1 q)
 .| b

And a and b will be none the wiser to the fact that q uses StateT internally.

Note to avoid the usage of void, evalStateP might be more useful.

Since: 0.2.1.0

runStatePS :: Monad m => s -> Pipe i o u (StateT s m) a -> Pipe i o u m (a, s) Source #

pAwaitF :: forall m i o u. MonadFree (PipeF i o u) m => m (Either u i) Source #

pYieldF :: forall m i o u. MonadFree (PipeF i o u) m => o -> m () Source #