Pull
A purely functional data structure that describes a process. This process
may evaluate actions in an effect type F, emit any number of output values
of type O (or None), and may a) terminate with a single result of type R;
or b) terminate abnormally by raising (inside the effect
or c) terminate because it was cancelled by another process,
or d) not terminate.
may evaluate actions in an effect type F, emit any number of output values
of type O (or None), and may a) terminate with a single result of type R;
or b) terminate abnormally by raising (inside the effect
F
) an exception,or c) terminate because it was cancelled by another process,
or d) not terminate.
Like types from other effect libraries, pulls are pure and immutable values.
They preserve referential transparency.
They preserve referential transparency.
=== Chunking ===
The output values of a pull are emitted not one by one, but in chunks.
A
a pull
values, which can wrap unboxed byte arrays -- avoiding boxing/unboxing costs.
The
the individual element level. Generally, working at the chunk level will
result in better performance but at the cost of more complex implementations
A
Chunk
is an immutable sequence with constant-time indexed lookup. For example,a pull
p: Pull[F, Byte, R]
internally operates and emits Chunk[Byte]
values, which can wrap unboxed byte arrays -- avoiding boxing/unboxing costs.
The
Pull
API provides mechanisms for working at both the chunk level andthe individual element level. Generally, working at the chunk level will
result in better performance but at the cost of more complex implementations
A pull only emits non-empty chunks.
However, chunks are not merely an operational matter of efficiency. Each
pull is emitted from a chunk atomically, which is to say, any errors or
interruptions in a pull can only happen between chunks, not within a
chunk. For instance, if creating a new chunk of values fails (raises an
uncaught exception) while creating an intermediate value, then it fails
to create the entire chunk and previous values are discarded.
pull is emitted from a chunk atomically, which is to say, any errors or
interruptions in a pull can only happen between chunks, not within a
chunk. For instance, if creating a new chunk of values fails (raises an
uncaught exception) while creating an intermediate value, then it fails
to create the entire chunk and previous values are discarded.
=== Evaluation ===
Like other functional effect types (e.g.
describes a process or computation. It is not a running process nor a
handle for the result of a spawned, running process, like
cats.effect.IO
), a pulldescribes a process or computation. It is not a running process nor a
handle for the result of a spawned, running process, like
scala.concurrent.Future
.A pull can be converted to a stream and then compiled to an effectful value.
For a
monad instance of
The result of that
the pull, in the order it emits them, using a fold function. Depending on that
function, outputs may be collected into a list (or vector or array or ...),
combined together into a single value, or just discarded altogether (by draining
the pull).
For a
Pull[F, O, Unit]
, the result of compilation is a combination, via themonad instance of
F
, of all the actions in the effect F
present in the pull.The result of that
F
action is the result of combining the outputs emitted bythe pull, in the order it emits them, using a fold function. Depending on that
function, outputs may be collected into a list (or vector or array or ...),
combined together into a single value, or just discarded altogether (by draining
the pull).
Compilation is pull-based, rather than push-based (hence the name of the datatype).
It is the compilation process itself, that determines when the evaluation
of each single effect can proceed or is held back. Effects and outputs later
in the pull are not performed or emitted, unless and until the compilation
calls for them.
It is the compilation process itself, that determines when the evaluation
of each single effect can proceed or is held back. Effects and outputs later
in the pull are not performed or emitted, unless and until the compilation
calls for them.
=== Resource scoping ===
The effects in a
the execution of the pull, may be shared by several pulls, and must be
properly finalised when no longer needed, regardless of whether the pull completed
successfully or not. A pull tracks its resources using '''scopes''', which register
how many pulls are actively using each resource, and finalises resources when no
longer used.
Pull
may operate on resources, which must be retained duringthe execution of the pull, may be shared by several pulls, and must be
properly finalised when no longer needed, regardless of whether the pull completed
successfully or not. A pull tracks its resources using '''scopes''', which register
how many pulls are actively using each resource, and finalises resources when no
longer used.
Some operations of the
or resource boundaries.
Pull
API can be used to introduce new resource scopes,or resource boundaries.
=== Functional typeclasses ===
The
for
Pull
data structure is a "free" implementation of Monad
and has an instancefor
cats.effect.kernel.Sync
.For any types
F[_]
and O
, a Pull[F, O, *]
holds the following laws:-
pure >=> f == f
-
f >=> pure == f
-
(f >=> g) >=> h == f >=> (g >=> h)
wheref >=> g
is defined asa => a flatMap f flatMap g
-
handleErrorWith(raiseError(e))(f) == f(e)
- Type Params
- F[_]
-
the type of effect that can be performed by this pull.
An effect type ofNothing
, also known infs2
by the aliasPure
,
indicates that this pull perform no effectful actions.
Note:Nothing
is a polykinded type, so it can also be
applied as an argument to the type parameterF[_]
. - O
-
The outputs emitted by this Pull. An output type of
Nothing
means
that this pull does not emit any outputs. - R
-
The type of result returned by this Pull upon successful termination.
An output type ofNothing
indicates that this pull cannot terminate
successfully: it may fail, be cancelled, or never terminate.
- Companion
- object
class Object
trait Matchable
class Any
Value members
Methods
def flatMap[F2 >: ([x] =>> F[x]) <: ([x] =>> Any), O2 >: O, R2](f: R => Pull[F2, O2, R2]): Pull[F2, O2, R2]
Applies the result of this pull to
f
and returns the result.This method returns a new composed pull, which will do as follows:
-
If
this
pull succeeds with a resultr
of type R, thef
function
is applied tor
, to build a new pullf(r)
, and the result pull
starts running that new pull. The composed pull will terminate (or not)
just as the new pullf(r)
does. -
If
this
pull fails or is interrupted, then the composed pull
terminates with that same failure or interruption. -
If evaluating
f(r)
to build the throws an exception, the result
is a pull that fails with that exception.
The composed pull emits all outputs emitted by
and if successful will start emitting the outputs from the generated pull.
this
pull,and if successful will start emitting the outputs from the generated pull.
This operation does not modify resource scope boundaries. The generated
and the composed pull will end on the same scope in which
post
pull starts running on the same scope in which this
pull ended,and the composed pull will end on the same scope in which
post
pull does. def >>[F2 >: ([x] =>> F[x]) <: ([x] =>> Any), O2 >: O, S](post: => Pull[F2, O2, S]): Pull[F2, O2, S]
Lazily appends the given
post
pull, to be run after this
pull.-
If
this
pull succeeds, then its result is discarded, thepost
pull is built, and starts running. The result ofpost
is
the result of the composed pull. -
If
this
pull raises an error or is interrupted, thepost
argument is
not evaluated and the composed pull ends just asthis
pull did.
In both cases, the effectful actions and outputs of the appended pull
consists of those outputs and actions from the first pull, followed by
those from the
consists of those outputs and actions from the first pull, followed by
those from the
post
pull, in the same order as they would come out of each pull.Since the
pulls, which are not built in memory until after the prefix has run.
This allows defining pulls recursively.
post
argument is lazy, this method can be used to build lazypulls, which are not built in memory until after the prefix has run.
This allows defining pulls recursively.
This operation does not add or remove any resource scope boundaries.
The
The composed pull ends on whatever scope the
The
post
pull runs on the same scope in which this
pull ended.The composed pull ends on whatever scope the
post
pull does.This is equivalent to
.flatMap(_ => post)
def handleErrorWith[F2 >: ([x] =>> F[x]) <: ([x] =>> Any), O2 >: O, R2 >: R](handler: Throwable => Pull[F2, O2, R2]): Pull[F2, O2, R2]
Allows to recover from any error raised by the evaluation of this pull.
This method returns a composed pull with the following semantics:
- If an error occurs, the supplied function is used to build a new handler
pull, and it starts running it. However, the pull cannot be resumed from
the point at which the error arose.
- If no error is raised, the resulting pull just does what
This method returns a composed pull with the following semantics:
- If an error occurs, the supplied function is used to build a new handler
pull, and it starts running it. However, the pull cannot be resumed from
the point at which the error arose.
- If no error is raised, the resulting pull just does what
this
pull does. def onComplete[F2 >: ([x] =>> F[x]) <: ([x] =>> Any), O2 >: O, R2](post: => Pull[F2, O2, R2]): Pull[F2, O2, R2]
Run
post
after this
, regardless of errors during this
:-
If
this
pull terminates successfully, then its result is discarded
and thepost
pull is run. However thepost
pull ends, be it in
success, error, interruption, is how the combined pull ends. -
If
this
pull fails, thepost
pull is run next. If thepost
pull
ends fails or is interrupted, that is how the combined pull ends.
However, if thepost
pull succeeds, then the combinedonComplete
pull
fails again with the error that was raised fromthis
pull. -
If
this
pull is interrupted, then thepost
error is never run
and the combined pull ends with that same interruption.
Returns a pull with the result wrapped in
or an error wrapped in
If
Right
,or an error wrapped in
Left
if the pull has raised an error.If
this
pull is interrupted, the attempted pull ends the same way.Maps the result of this pull with the
f
mapping funciton.If
is applied to its result
mapped pull. However, if the evaluation of
mapped pull fails with that error.
this
pull ends in success with a result r
, then the function f
is applied to its result
r
, and the image f(r)
is the result of themapped pull. However, if the evaluation of
f(r)
throws an error, themapped pull fails with that error.
Note: for some simple cases of Pull, the
applied, or discarded, before the pull starts being run.
map
function may be eagerlyapplied, or discarded, before the pull starts being run.
If
this
pull terminates abnormally, so does the mapped pull.Discards the result of this pull.
If
pull returns the unit
the same as
this
pull ends in success, its result is discarded and the voidedpull returns the unit
()
value. Otherwise, the voided pull just doesthe same as
this
pull does.Alias for
this.map(_ => () )
.Replaces the result of this pull with the given constant value.
If
pull succeeds with the
Otherwise, if
ends the same way.
If
this
pull succeeds, then its result is discarded and the resultingpull succeeds with the
s
value as its result.Otherwise, if
this
pull fails or is interrupted, then the result pullends the same way.
Alias for
_.map(_ => o2)
.- Type Params
- S
-
The type of the constant,
- Value Params
- s
-
The new result value of the pull