Strict, finite sequence of values that allows index-based random access of elements.
Strict, finite sequence of values that allows index-based random access of elements.
Chunk
s can be created from a variety of collection types using methods on the Chunk
companion
(e.g., Chunk.vector
, Chunk.seq
, Chunk.array
). Additionally, the Chunk
companion
defines a subtype of Chunk
for each primitive type, using an unboxed primitive array.
To work with unboxed arrays, use methods like toBytes
to convert a Chunk[Byte]
to a Chunk.Bytes
and then access the array directly.
The operations on Chunk
are all defined strictly. For example, c.map(f).map(g).map(h)
results in
intermediate chunks being created (1 per call to map
).
Represents multiple (>1) exceptions were thrown.
Indicates that a stream evaluates no effects but unlike Pure, may raise errors.
Indicates that a stream evaluates no effects but unlike Pure, may raise errors.
Uninhabited.
A Stream[Fallible,O]
can be safely converted to a Stream[F,O]
for all F
via s.lift[F]
,
provided an ApplicativeError[F, Throwable]
is available.
Alias for Nothing
which works better with type inference.
A stream transformation represented as a function from stream to stream.
A stream transformation represented as a function from stream to stream.
Pipes are typically applied with the through
operation on Stream
.
A stream transformation that combines two streams in to a single stream, represented as a function from two streams to a single stream.
A stream transformation that combines two streams in to a single stream, represented as a function from two streams to a single stream.
Pipe2
s are typically applied with the through2
operation on Stream
.
A p: Pull[F,O,R]
reads values from one or more streams, returns a
result of type R
, and produces a Stream[F,O]
when calling p.stream
.
A p: Pull[F,O,R]
reads values from one or more streams, returns a
result of type R
, and produces a Stream[F,O]
when calling p.stream
.
Any resources acquired by p
are freed following the call to stream
.
Laws:
Pull
forms a monad in R
with pure
and flatMap
:
pure >=> f == f
f >=> pure == f
(f >=> g) >=> h == f >=> (g >=> h)
where f >=> g
is defined as a => a flatMap f flatMap g
raiseError
is caught by handleErrorWith
:
handleErrorWith(raiseError(e))(f) == f(e)
Indicates that a stream evaluates no effects.
Indicates that a stream evaluates no effects.
A Stream[Pure,O]
can be safely converted to a Stream[F,O]
for all F
.
Witnesses that F
supports raising throwables.
Witnesses that F
supports raising throwables.
An instance of RaiseThrowable
is available for any F
which has an
ApplicativeError[F, Throwable]
instance. Alternatively, an instance
is available for the uninhabited type Fallible
.
Represents a period of stream execution in which resources are acquired and released.
Represents a period of stream execution in which resources are acquired and released.
Note: this type is generally used to implement low-level actions that manipulate resource lifetimes and hence, isn't generally used by user-level code.
A stream producing output of type O
and which may evaluate F
effects.
A stream producing output of type O
and which may evaluate F
effects.
- Purely functional a value of type Stream[F, O]
_describes_ an effectful computation.
A function that returns a Stream[F, O]
builds a _description_ of an effectful computation,
but does not perform them. The methods of the Stream
class derive new descriptions from others.
This is similar to cats.effect.IO
, monix.Task
, or scalaz.zio.IO
.
- Pull: to evaluate a stream, a consumer pulls its values from it, by repeatedly performing one pull step at a time.
Each step is a F
-effectful computation that may yield some O
values (or none), and a stream from which to continue pulling.
The consumer controls the evaluation of the stream, which effectful operations are performed, and when.
- Non-Strict: stream evaluation only pulls from the stream a prefix large enough to compute its results.
Thus, although a stream may yield an unbounded number of values or, after successfully yielding several values,
either raise an error or hang up and never yield any value, the consumer need not reach those points of failure.
For the same reason, in general, no effect in F
is evaluated unless and until the consumer needs it.
- Abstract: a stream needs not be a plain finite list of fixed effectful computations in F. It can also represent an input or output connection through which data incrementally arrives. It can represent an effectful computation, such as reading the system's time, that can be re-evaluated as often as the consumer of the stream requires.
There are some special properties or cases of streams:
F
is Pure, which indicates that it evaluates no effects.We can sometimes think of streams, naively, as lists of O
elements with F
-effects.
This is particularly true for pure streams, which are instances of Stream
which use the Pure effect type.
We can convert every pure and finite stream into a List[O]
using the .toList
method.
Also, we can convert pure infinite streams into instances of the Stream[O]
class from the Scala standard library.
A method of the Stream
class is pure if it can be applied to pure streams. Such methods are identified
in that their signature includes no type-class constraint (or implicit parameter) on the F
method.
Pure methods in Stream[F, O]
can be projected naturally to methods in the List
class, which means
that we can applying the stream's method and converting the result to a list gets the same result as
first converting the stream to a list, and then applying list methods.
Some methods that project directly to list methods are, are map
, filter
, takeWhile
, etc.
There are other methods, like exists
or find
, that in the List
class they return a value or an Option
,
but their stream counterparts return an (either empty or singleton) stream.
Other methods, like zipWithPrevious
, have a more complicated but still pure translation to list methods.
Laws (using infix syntax):
append
forms a monoid in conjunction with empty
:
empty append s == s
and s append empty == s
.(s1 append s2) append s3 == s1 append (s2 append s3)
And cons
is consistent with using ++
to prepend a single chunk:
s.cons(c) == Stream.chunk(c) ++ s
Stream.raiseError
propagates until being caught by handleErrorWith
:
Stream.raiseError(e) handleErrorWith h == h(e)
Stream.raiseError(e) ++ s == Stream.raiseError(e)
Stream.raiseError(e) flatMap f == Stream.raiseError(e)
Stream
forms a monad with emit
and flatMap
:
Stream.emit >=> f == f
(left identity)f >=> Stream.emit === f
(right identity - note weaker equality notion here)(f >=> g) >=> h == f >=> (g >=> h)
(associativity)
where Stream.emit(a)
is defined as chunk(Chunk.singleton(a)) and
f >=> g is defined as
a => a flatMap f flatMap g
The monad is the list-style sequencing monad:
(a ++ b) flatMap f == (a flatMap f) ++ (b flatMap f)
Stream.empty flatMap f == Stream.empty
Note: since the chunk structure of the stream is observable, and
s flatMap Stream.emit
produces a stream of singleton chunks,
the right identity law uses a weaker notion of equality, ===
which
normalizes both sides with respect to chunk structure:
(s1 === s2) = normalize(s1) == normalize(s2)
where ==
is full equality
(a == b
iff f(a)
is identical to f(b)
for all f
)
normalize(s)
can be defined as s.flatMap(Stream.emit)
, which just
produces a singly-chunked stream from any input stream s
.
For instance, for a stream s
and a function f: A => B
,
- the result of s.map(f)
is a Stream with the same _chunking_ as the s
; wheras...
- the result of s.flatMap(x => S.emit(f(x)))
is a Stream structured as a sequence of singleton chunks.
The latter is using the definition of map
that is derived from the Monad
instance.
This is not unlike equality for maps or sets, which is defined by which elements they contain,
not by how these are spread between a tree's branches or a hashtable buckets.
However, a Stream
structure can be _observed_ through the chunks
method,
so two streams "_equal_" under that notion may give different results through this method.
Note: For efficiency Stream.map
function operates on an entire
chunk at a time and preserves chunk structure, which differs from
the map
derived from the monad (s map f == s flatMap (f andThen Stream.emit)
)
which would produce singleton chunk. In particular, if f
throws errors, the
chunked version will fail on the first chunk with an error, while
the unchunked version will fail on the first element with an error.
Exceptions in pure code like this are strongly discouraged.
A pipe that converts a stream to a Stream[F,Unit]
.
A pipe that converts a stream to a Stream[F,Unit]
.
Sinks are typically applied with the to
operation on Stream
.
(Since version 1.0.2) Use Pipe[F, I, Unit] instead
Provides utilities for compressing/decompressing byte streams.
Provides several concurrency primitives.
Provides several concurrency primitives. *
Provides various cryptographic hashes as pipes.
Provides utilities for working with streams of text (e.g., encoding byte streams to strings).