fs2

package fs2

Type members

Classlikes

abstract class Chunk[+O] extends Serializable with ChunkPlatform[O]
Strict, finite sequence of values that allows index-based random access of elements.
Chunks can be created from a variety of collection types using methods on the Chunk companion
(e.g., Chunk.array, Chunk.seq, Chunk.vector).
Chunks can be appended via the ++ method. The returned chunk is a composite of the input
chunks -- that is, there's no copying of the source chunks. For example, Chunk(1, 2) ++ Chunk(3, 4) ++ Chunk(5, 6)
returns a Chunk.Queue(Chunk(1, 2), Chunk(3, 4), Chunk(5, 6)). As a result, indexed based lookup of
an appended chunk is O(number of underlying chunks). In the worse case, where each constituent chunk
has size 1, indexed lookup is O(size). To restore O(1) lookup, call compact, which copies all the underlying
chunk elements to a single array backed chunk. Note compact requires a ClassTag of the element type.
Alternatively, a collection of chunks can be directly copied to a new array backed chunk via
Chunk.concat(chunks). Like compact, Chunk.concat requires a ClassTag for the element type.
Various subtypes of Chunk are exposed for efficiency reasons:
- Chunk.Singleton
- Chunk.ArraySlice
- Chunk.Queue
In particular, calling .toArraySlice on a chunk returns a Chunk.ArraySlice, which provides
access to the underlying backing array, along with an offset and length, referring to a slice
of that array.
Companion
object
object Chunk extends CollectorK[[O] =>> Chunk[O]] with ChunkCompanionPlatform
Companion
class
trait Collector[-A]
Supports building a result of type Out from zero or more Chunk[A].
This is similar to the standard library collection builders but optimized for
building a collection from a stream.
The companion object provides implicit conversions (methods starting with supports),
which adapts various collections to the Collector trait.
Companion
object
object Collector extends CollectorPlatform
Companion
class
trait CollectorK[+C <: ([_$4] =>> Any)]
Mixin trait for companions of collections that can build a C[A] for all A.
Companion
object
object CollectorK
Companion
class
@implicitNotFound("Cannot find an implicit Compiler[F, G]. This typically means you need a Concurrent[F] in scope")
sealed trait Compiler[F <: ([_$1] =>> Any), G <: ([_$2] =>> Any)]
Provides compilation of a Stream[F, O] to a G[*].
In the most common case, F = G = IO or another "fully featured" effect type. However, there
are other common instantiations like F = Pure, G = Id, which allows compiling a
Stream[Pure, A] in to pure values.
For the common case where F = G, the target implicit constructor provides an instance of
Compiler[F, F] -- target requires a Compiler.Target[F] instance. The Compiler.Target[F] is a
super charged MonadErrorThrow[F], providing additional capabilities needed for stream compilation.
Compiler.Target[F] instances are given for all F[_] which have:
- Concurrent[F] instances
- both MonadCancelThrow[F] and Sync[F] intances
- only Sync[F] instances
Support for stream interruption requires compilation to an effect which has a Concurrent instance.
Companion
object
object Compiler extends CompilerLowPriority
Companion
class
case class CompositeFailure(head: Throwable, tail: NonEmptyList[Throwable]) extends Throwable
Represents multiple (>1) exceptions were thrown.
Companion
object
Companion
class
sealed trait Fallible[A]
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.
Companion
object
object Fallible
Companion
class
object Pipe
sealed abstract class Pull[+F <: ([_$1] =>> Any), +O, +R]
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)
Companion
object
object Pull extends PullLowPriority
Companion
class
@implicitNotFound("Cannot find an implicit value for RaiseThrowable[${F}]: an instance is available for any F which has an ApplicativeError[F, Throwable] instance or for F = Fallible. If getting this error for a non-specific F, try manually supplying the type parameter (e.g., Stream.raiseError[IO](t) instead of Stream.raiseError(t)). If getting this error when working with pure streams, use F = Fallible.")
trait RaiseThrowable[F <: ([_$1] =>> Any)]
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.
Companion
object
Companion
class
final class Stream[+F <: ([_$1] =>> Any), +O]
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 how effect types like cats.effect.IO and monix.Task build descriptions of
    computations.
  • '''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.
=== Special properties for streams ===
There are some special properties or cases of streams:
- A stream is '''finite''' if we can reach the end after a limited number of pull steps,
which may yield a finite number of values. It is '''empty''' if it terminates and yields no values.
- A '''singleton''' stream is a stream that ends after yielding one single value.
- A '''pure''' stream is one in which the F is Pure, which indicates that it evaluates no effects.
- A '''never''' stream is a stream that never terminates and never yields any value.
== Pure Streams and operations ==
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 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.
== Type-Class instances and laws of the Stream Operations ==
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
== Technical notes==
''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.
Companion
object
object Stream extends StreamLowPriority
Companion
class
object compression
Provides utilities for compressing/decompressing byte streams.
object hash
Provides various cryptographic hashes as pipes.
object text
Provides utilities for working with streams of text (e.g., encoding byte streams to strings).

Types

type INothing <: Nothing
Alias for Nothing which works better with type inference.
type Pipe[F <: ([_$1] =>> Any), -I, +O] = Stream[F, I] => Stream[F, O]
A stream transformation represented as a function from stream to stream.
Pipes are typically applied with the through operation on Stream.
type Pipe2[F <: ([_$2] =>> Any), -I, -I2, +O] = (Stream[F, I], Stream[F, I2]) => Stream[F, O]
A stream transformation that combines two streams in to a single stream,
represented as a function from two streams to a single stream.
Pipe2s are typically applied with the through2 operation on Stream.
type Pure[A] <: Nothing
Indicates that a stream evaluates no effects.
A Stream[Pure,O] can be safely converted to a Stream[F,O] for all F.