| Copyright | (c) Justin Le 2019 |
|---|---|
| License | BSD3 |
| Maintainer | justin@jle.im |
| Stability | experimental |
| Portability | non-portable |
| Safe Haskell | Safe-Inferred |
| Language | Haskell2010 |
Data.Conduino.Internal
Description
Internal module exposing the internals of Pipe, including its
underlying representation and base functor.
Synopsis
- newtype Pipe i o u m a = Pipe {}
- data PipeF i o u a
- awaitEither :: Pipe i o u m (Either u i)
- yield :: o -> Pipe i o u m ()
- yieldLazy :: o -> Pipe i o u m ()
- trimapPipe :: (i -> j) -> (p -> o) -> (u -> v) -> Pipe j p v m a -> Pipe i o u m a
- trimapPipeF :: (i -> j) -> (p -> o) -> (u -> v) -> PipeF j p v a -> PipeF i o u a
- mapInput :: (i -> j) -> Pipe j o u m a -> Pipe i o u m a
- mapOutput :: (p -> o) -> Pipe i p u m a -> Pipe i o u m a
- mapUpRes :: (u -> v) -> Pipe i o v m a -> Pipe i o u m a
- hoistPipe :: (Monad m, Monad n) => (forall x. m x -> n x) -> Pipe i o u m a -> Pipe i o u n a
- type RecPipe i o u = FreeT (PipeF i o u)
- toRecPipe :: Monad m => Pipe i o u m a -> RecPipe i o u m a
- fromRecPipe :: Monad m => RecPipe i o u m a -> Pipe i o u m a
- 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
- runStateP :: Monad m => s -> Pipe i o u (StateT s m) a -> Pipe i o u m (a, s)
- runStatePS :: Monad m => s -> Pipe i o u (StateT s m) a -> Pipe i o u m (a, s)
- pAwaitF :: forall m i o u. MonadFree (PipeF i o u) m => m (Either u i)
- pYieldF :: forall m i o u. MonadFree (PipeF i o u) m => o -> m ()
Documentation
newtype Pipe i o u m a Source #
Similar to a conduit from the conduit package.
For a , you have:Pipe i o u m a
i: Type of input stream (the things you canawait)o: Type of output stream (the things youyield)u: Type of the result of the upstream pipe (Outputted when upstream pipe terminates)m: Underlying monad (the things you canlift)a: Result type when pipe terminates (outputted when finished, withpureorreturn)
Some specializations:
- If
iis(), 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
oisVoid, the pipe is a sink --- it will neveryieldanything downstream. It will consume items from things upstream, and produce a result (a) if and when it terminates. - If
uisVoid, then the pipe's upstream is limitless, and never terminates. This means that you can useawaitSurelyinstead ofawait, to get await a value that is guaranteed to come. You'll get aniinstead of a.Maybei - If
aisVoid, 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 sorunPipewill also never terminate. If it is a source, it means that if you chain something downstream with.|, that downstream pipe can useawaitSurelyto 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.
Instances
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
MonadTransandMonadIOinstances thatFTgives. - Ending with a result is implemented by the
Applicativeinstance'spurethatFTgives. - Applicative and monadic sequenceing "after a pipe is done" is
implemented by the
ApplicativeandMonadinstances thatFTgives.
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.
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.
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 #
runStateP, but for Control.Monad.Trans.State.Strict.
Since: 0.2.1.0