In this guide, we’ll explore the concept of a Stream<A, E, R>. A Stream is a program description that, when executed, can emit zero or more values of type A, handle errors of type E, and operates within a context of type R.
Use Cases
Streams are particularly handy whenever you’re dealing with sequences of values over time. They can serve as replacements for observables, node streams, and AsyncIterables.
What is a Stream?
Think of a Stream as an extension of an Effect. While an Effect<A, E, R> represents a program that requires a context of type R, may encounter an error of type E, and always produces a single result of type A, a Stream<A, E, R> takes this further by allowing the emission of zero or more values of type A.
To clarify, let’s examine some examples using Effect:
In each case, the Effect always ends with exactly one value. There is no variability; you always get one result.
Understanding Streams
Now, let’s shift our focus to Stream. A Stream represents a program description that shares similarities with Effect, it requires a context of type R, may signal errors of type E, and yields values of type A. However, the key distinction is that it can yield zero or more values.
Here are the possible scenarios for a Stream:
An Empty Stream: It can end up empty, representing a stream with no values.
A Single-Element Stream: It can represent a stream with just one value.
A Finite Stream of Elements: It can represent a stream with a finite number of values.
An Infinite Stream of Elements: It can represent a stream that continues indefinitely, essentially an infinite stream.
In summary, a Stream is a versatile tool for representing programs that may yield multiple values, making it suitable for a wide range of tasks, from processing finite lists to handling infinite sequences.