Appends the given stream to the end of the source, effectively concatenating them.
Appends the given stream to the end of the source, effectively concatenating them.
Example:
import monix.eval.Task // Yields 1, 2, 3, 4 Iterant[Task].of(1, 2) ++ Iterant[Task].of(3, 4)
is the (right hand side) lazily evaluated iterant to concatenate at the end of this iterant.
Appends a stream to the end of the source, effectively concatenating them.
Appends a stream to the end of the source, effectively concatenating them.
The right hand side is suspended in the F[_]
data type, thus
allowing for laziness.
Example:
import monix.eval.Task // Yields 1, 2, 3, 4 Iterant[Task].of(1, 2) ++ Task.eval { Iterant[Task].of(3, 4) }
is the iterant to append at the end of our source.
Prepends an element to the iterant, returning a new
iterant that will start with the given head
and then
continue with the source.
Prepends an element to the iterant, returning a new
iterant that will start with the given head
and then
continue with the source.
Example:
import monix.eval.Task // Yields 1, 2, 3, 4 1 +: Iterant[Task].of(2, 3, 4)
is the element to prepend at the start of this iterant
Appends the right hand side element to the end of this iterant.
Appends the right hand side element to the end of this iterant.
Example:
import monix.eval.Task // Yields 1, 2, 3, 4 Iterant[Task].of(1, 2, 3) :+ 4
is the element to append at the end
Converts the source Iterant
that emits A
elements into an
iterant that emits Either[Throwable, A]
, thus materializing
whatever error that might interrupt the stream.
Converts the source Iterant
that emits A
elements into an
iterant that emits Either[Throwable, A]
, thus materializing
whatever error that might interrupt the stream.
Example:
import monix.eval.Task import monix.execution.exceptions.DummyException // Yields Right(1), Right(2), Right(3) Iterant[Task].of(1, 2, 3).attempt // Yields Right(1), Right(2), Left(DummyException()) (Iterant[Task].of(1, 2) ++ Iterant[Task].raiseError[Int](DummyException("dummy"))).attempt
Optimizes the access to the source by periodically gathering items emitted into batches of the specified size and emitting NextBatch nodes.
Optimizes the access to the source by periodically gathering items emitted into batches of the specified size and emitting NextBatch nodes.
For this operation we have this law:
source.batched(16) <-> source
This means that the result will emit exactly what the source
emits, however the underlying representation will be different,
the emitted notes being of type NextBatch
, wrapping arrays
with the length equal to the given count
.
Very similar in behavior with bufferTumbling, however the batches are implicit, not explicit. Useful for optimization.
Returns an iterant that emits buffers of items it collects from the source iterant.
Returns an iterant that emits buffers of items it collects from
the source iterant. The resulting iterant emits buffers
every skip
items, each containing count
items.
If the source iterant completes, then the current buffer gets signaled downstream. If the source triggers an error then the current buffer is being dropped and the error gets propagated immediately.
For count
and skip
there are 3 possibilities:
skip == count
, then there are no items dropped and
no overlap, the call being equivalent to buffer(count)
skip < count
, then overlap between buffers
happens, with the number of elements being repeated being
count - skip
skip > count
, then skip - count
elements start
getting dropped between windowsExample:
import monix.eval.Coeval val source = Iterant[Coeval].of(1, 2, 3, 4, 5, 6, 7) // Yields Seq(1, 2, 3), Seq(4, 5, 6), Seq(7) source.bufferSliding(3, 3) // Yields Seq(1, 2, 3), Seq(5, 6, 7) source.bufferSliding(3, 4) // Yields Seq(1, 2, 3), Seq(3, 4, 5), Seq(5, 6, 7) source.bufferSliding(3, 2)
the maximum size of each buffer before it should be emitted
how many items emitted by the source iterant should
be skipped before starting a new buffer. Note that when
skip and count are equal, this is the same operation as
bufferTumbling(count)
Periodically gather items emitted by an iterant into bundles and emit these bundles rather than emitting the items one at a time.
Periodically gather items emitted by an iterant into bundles
and emit these bundles rather than emitting the items one at a
time. This version of buffer
is emitting items once the
internal buffer has reached the given count.
If the source iterant completes, then the current buffer gets signaled downstream. If the source triggers an error then the current buffer is being dropped and the error gets propagated immediately.
import monix.eval.Coeval // Yields Seq(1, 2, 3), Seq(4, 5, 6), Seq(7) Iterant[Coeval].of(1, 2, 3, 4, 5, 6, 7).bufferTumbling(3)
the maximum size of each buffer before it should be emitted
bufferSliding for the more flexible version that allows
to specify a skip
argument.
Builds a new iterant by applying a partial function to all elements of the source on which the function is defined.
Builds a new iterant by applying a partial function to all elements of the source on which the function is defined.
Example:
import monix.eval.Task // Yields 2, 4, 6 Iterant[Task].of(1, 2, 3, 4, 5, 6) .map { x => Option(x).filter(_ % 2 == 0) } .collect { case Some(x) => x }
the element type of the returned iterant.
the partial function that filters and maps the iterant
a new iterant resulting from applying the partial
function pf
to each element on which it is defined and
collecting the results. The order of the elements is
preserved.
Upon evaluation of the result, consumes this iterant to completion.
Upon evaluation of the result, consumes this iterant to completion.
Example:
import cats.implicits._ import monix.eval.Task // Whatever... val iterant = Iterant[Task].range(0, 10000) val onFinish: Task[Unit] = iterant.completedL >> Task.eval(println("Done!"))
Alias for concat.
Alias for flatMap.
Create a ConsumerF value that can be used to consume events from the channel.
Create a ConsumerF value that can be used to consume events from the channel.
The returned value is a Resource, because a consumer can be unsubscribed from the channel early, with its internal buffer being garbage collected and the finalizers of the source being triggered.
import monix.eval.Task import monix.tail.Iterant.Consumer def sum(channel: Consumer[Task, Int], acc: Long = 0): Task[Long] = channel.pull.flatMap { case Right(a) => sum(channel, acc + a) case Left(None) => Task.pure(acc) case Left(Some(e)) => Task.raiseError(e) } Iterant[Task].range(0, 10000).consume.use { consumer => sum(consumer) }
consumeWithConfig for fine tuning the internal buffer of the created consumer
Version of consume that allows for fine tuning the underlying buffer used.
Version of consume that allows for fine tuning the underlying buffer used.
There are two parameters that can be configured:
is the configuration object for fine tuning the behavior of the created consumer, see ConsumerF.Config1
Counts the total number of elements emitted by the source.
Counts the total number of elements emitted by the source.
Example:
import cats.effect.IO // Yields 100 Iterant[IO].range(0, 100).countL // Yields 1 Iterant[IO].pure(1).countL // Yields 0 Iterant[IO].empty[Int].countL
Suppress duplicate consecutive items emitted by the source.
Suppress duplicate consecutive items emitted by the source.
Example:
import cats.implicits._ import monix.eval.Coeval // Yields 1, 2, 1, 3, 2, 4 Iterant[Coeval].of(1, 1, 1, 2, 2, 1, 1, 3, 3, 3, 2, 2, 4, 4, 4) .distinctUntilChanged
Duplication is detected by using the equality relationship
provided by the cats.Eq
type class. This allows one to
override the equality operation being used (e.g. maybe the
default .equals
is badly defined, or maybe you want reference
equality, so depending on use case).
Monix prefers to work with cats.Eq for assessing the equality of elements that have an ordering defined, instead of scala.math.Equiv.
We do this because Scala's Equiv
has a default instance defined
that's based on universal equality and that's a big problem, because
when using the Eq
type class, it is universal equality that we
want to avoid and there have been countless of bugs in the ecosystem
related to both universal equality and Equiv
. Thankfully people
are working to fix it.
We also do this for consistency, as Monix is now building on top of Cats. This may change in the future, depending on what happens with typelevel/cats#2455.
Defining Eq
instance is easy and we can use universal equality
in our definitions as well:
import cats.Eq case class Address(host: String, port: Int) implicit val eqForAddress: Eq[Address] = Eq.fromUniversalEquals
is the cats.Eq
instance that defines equality for A
Given a function that returns a key for each element emitted by the source, suppress consecutive duplicate items.
Given a function that returns a key for each element emitted by the source, suppress consecutive duplicate items.
Example:
import cats.implicits._ import monix.eval.Coeval // Yields 1, 2, 3, 4 Iterant[Coeval].of(1, 3, 2, 4, 2, 3, 5, 7, 4) .distinctUntilChangedByKey(_ % 2)
Duplication is detected by using the equality relationship
provided by the cats.Eq
type class. This allows one to
override the equality operation being used (e.g. maybe the
default .equals
is badly defined, or maybe you want reference
equality, so depending on use case).
Monix prefers to work with cats.Eq for assessing the equality of elements that have an ordering defined, instead of scala.math.Equiv.
We do this because Scala's Equiv
has a default instance defined
that's based on universal equality and that's a big problem, because
when using the Eq
type class, it is universal equality that we
want to avoid and there have been countless of bugs in the ecosystem
related to both universal equality and Equiv
. Thankfully people
are working to fix it.
We also do this for consistency, as Monix is now building on top of Cats. This may change in the future, depending on what happens with typelevel/cats#2455.
Defining Eq
instance is easy and we can use universal equality
in our definitions as well:
import cats.Eq case class Address(host: String, port: Int) implicit val eqForAddress: Eq[Address] = Eq.fromUniversalEquals
is a function that returns a K
key for each element,
a value that's then used to do the deduplication
is the cats.Eq
instance that defines equality for
the key type K
Drops the first n
elements (from the start).
Drops the first n
elements (from the start).
Example:
import monix.eval.Task // Yields 4, 5 Iterant[Task].of(1, 2, 3, 4, 5).drop(3)
the number of elements to drop
a new iterant that drops the first n elements emitted by the source
Drops the last n
elements (from the end).
Drops the last n
elements (from the end).
Example:
import monix.eval.Task // Yields 1, 2 Iterant[Task].of(1, 2, 3, 4, 5).dropLast(3)
the number of elements to drop
a new iterant that drops the last n elements emitted by the source
Drops the longest prefix of elements that satisfy the given predicate and returns a new iterant that emits the rest.
Drops the longest prefix of elements that satisfy the given predicate and returns a new iterant that emits the rest.
Example:
import monix.eval.Task // Yields 4, 5 Iterant[Task].of(1, 2, 3, 4, 5).dropWhile(_ < 4)
is the predicate used to test whether the current
element should be dropped, if true
, or to interrupt
the dropping process, if false
a new iterant that drops the elements of the source
until the first time the given predicate returns false
Drops the longest prefix of elements that satisfy the given function and returns a new Iterant that emits the rest.
Drops the longest prefix of elements that satisfy the given function and returns a new Iterant that emits the rest.
In comparison with dropWhile, this version accepts a function that takes an additional parameter: the zero-based index of the element.
Example:
import monix.eval.Task // Yields 3, 4, 5 Iterant[Task].of(1, 2, 3, 4, 5) .dropWhileWithIndex((value, index) => value >= index * 2)
is the predicate used to test whether the current
element should be dropped, if true
, or to interrupt
the dropping process, if false
a new iterant that drops the elements of the source
until the first time the given predicate returns false
Dumps incoming events to standard output with provided prefix.
Dumps incoming events to standard output with provided prefix.
Utility that can be used for debugging purposes.
Example:
import monix.eval.Task import monix.execution.Scheduler.Implicits.global Iterant[Task].range(0, 4) .dump("O") .completedL // 0: O --> next-batch --> 0 // 1: O --> next-batch --> 1 // 2: O --> next-batch --> 2 // 3: O --> next-batch --> 3 // 4: O --> halt --> no error
Returns true
in case the given predicate is satisfied by any
of the emitted items, or false
in case the end of the stream
has been reached with no items satisfying the given predicate.
Returns true
in case the given predicate is satisfied by any
of the emitted items, or false
in case the end of the stream
has been reached with no items satisfying the given predicate.
Example:
import monix.eval.Coeval val source = Iterant[Coeval].of(1, 2, 3, 4) // Yields true source.existsL(_ % 2 == 0) // Yields false source.existsL(_ % 7 == 0)
is a predicate function that's going to test each item emitted by the source until we get a positive match for one of them or until the stream ends
true
if any of the items satisfies the given predicate
or false
if none of them do
Filters the iterant by the given predicate function, returning only those elements that match.
Filters the iterant by the given predicate function, returning only those elements that match.
Example:
import monix.eval.Task // Yields 2, 4, 6 Iterant[Task].of(1, 2, 3, 4, 5, 6).filter(_ % 2 == 0)
the predicate used to test elements.
a new iterant consisting of all elements that satisfy the given predicate. The order of the elements is preserved.
Given a predicate, finds the first item that satisfies it,
returning Some(a)
if available, or None
otherwise.
Given a predicate, finds the first item that satisfies it,
returning Some(a)
if available, or None
otherwise.
import monix.eval.Coeval // Yields Some(2) Iterant[Coeval].of(1, 2, 3, 4).findL(_ % 2 == 0) // Yields None Iterant[Coeval].of(1, 2, 3, 4).findL(_ > 10)
The stream is traversed from beginning to end, the process being interrupted as soon as it finds one element matching the predicate, or until the stream ends.
is the function to test the elements of the source
either Some(value)
in case value
is an element
emitted by the source, found to satisfy the predicate,
or None
otherwise
Applies the function to the elements of the source and concatenates the results.
Applies the function to the elements of the source and concatenates the results.
This operation is the monadic "bind", with all laws it entails.
Also note that the implementation can use constant memory depending on usage, thus it can be used in tail recursive loops.
Example:
import monix.eval.Task // Effectively equivalent with .filter Iterant[Task].of(1, 2, 3, 4, 5, 6).flatMap { elem => if (elem % 2 == 0) Iterant[Task].pure(elem) else Iterant[Task].empty[Int] }
is the function mapping elements from the source to iterants
Given an Iterant
that generates Iterant
elements, concatenates
all the generated iterants.
Given an Iterant
that generates Iterant
elements, concatenates
all the generated iterants.
Equivalent with: source.flatMap(x => x)
Given evidence that type A
has a cats.Monoid
implementation,
folds the stream with the provided monoid definition.
Given evidence that type A
has a cats.Monoid
implementation,
folds the stream with the provided monoid definition.
For streams emitting numbers, this effectively sums them up. For strings, this concatenates them.
Example:
import cats.implicits._ import monix.eval.Task // Yields 10 Iterant[Task].of(1, 2, 3, 4).foldL // Yields "1234" Iterant[Task].of("1", "2", "3", "4").foldL
Note, in case you don't have a Monoid
instance in scope,
but you feel like you should, try one of these imports:
// everything import cats.implicits._ // a la carte: import cats.instances.all._
is the cats.Monoid
type class instance that's needed
in scope for folding the source
the result of combining all elements of the source,
or the defined Monoid.empty
element in case the
stream is empty
Left associative fold using the function op
.
Left associative fold using the function op
.
On execution the stream will be traversed from left to right, and the given function will be called with the prior result, accumulating state until the end, when the summary is returned.
Example:
import monix.eval.Task // Yields 15 (1 + 2 + 3 + 4 + 5) Iterant[Task].of(1, 2, 3, 4, 5).foldLeftL(0)(_ + _)
is the start value
is the binary operator
the result of inserting op
between consecutive
elements of this iterant, going from left to right with
the seed
as the start value, or seed
if the iterant
is empty.
Lazily fold the stream to a single value from the right.
Lazily fold the stream to a single value from the right.
This is the common foldr
operation from Haskell's Foldable
,
or foldRight
from cats.Foldable
, but with the difference that
Iterant
is a lazy data type and thus it has to operate in the F[_]
context.
Here's for example how existsL, forallL and ++
could
be expressed in terms of foldRightL
:
import cats.implicits._ import cats.effect.Sync def exists[F[_], A](fa: Iterant[F, A], p: A => Boolean) (implicit F: Sync[F]): F[Boolean] = { fa.foldRightL(F.pure(false)) { (a, next) => if (p(a)) F.pure(true) else next } } def forall[F[_], A](fa: Iterant[F, A], p: A => Boolean) (implicit F: Sync[F]): F[Boolean] = { fa.foldRightL(F.pure(true)) { (a, next) => if (!p(a)) F.pure(false) else next } } def concat[F[_], A](lh: Iterant[F, A], rh: Iterant[F, A]) (implicit F: Sync[F]): Iterant[F, A] = { Iterant.suspend[F, A] { lh.foldRightL(F.pure(rh)) { (a, rest) => F.pure(Iterant.nextS(a, rest)) } } }
In this example we are short-circuiting the processing in case we find the one element that we are looking for, otherwise we keep traversing the stream until the end, finally returning the default value in case we haven't found what we were looking for.
is the starting value; in case f
is a binary operator,
this is typically its left-identity (zero)
is the function to be called that folds the list, receiving the current element being iterated on (first param) and the (lazy) result from recursively combining the rest of the list (second param)
Left associative fold using the function op
that can be
short-circuited.
Left associative fold using the function op
that can be
short-circuited.
On execution the stream will be traversed from left to right,
and the given function will be called with the prior result,
accumulating state either until the end, or until op
returns
a Right
result, when the summary is returned.
The results are returned in the F[_]
functor context, meaning
that we can have lazy or asynchronous processing and we can
suspend side effects, depending on the F
data type being used.
Example using cats.effect.IO
:
import cats.implicits._ import cats.effect.IO // Sums first 10 items Iterant[IO].range(0, 1000).foldWhileLeftEvalL(IO((0, 0))) { case ((sum, count), e) => IO { val next = (sum + e, count + 1) if (count + 1 < 10) Left(next) else Right(next) } } // Implements exists(predicate) Iterant[IO].of(1, 2, 3, 4, 5).foldWhileLeftEvalL(IO(false)) { (default, e) => IO { if (e == 3) Right(true) else Left(default) } } // Implements forall(predicate) Iterant[IO].of(1, 2, 3, 4, 5).foldWhileLeftEvalL(IO(true)) { (default, e) => IO { if (e != 3) Right(false) else Left(default) } }
is the start value
is the binary operator returning either Left
,
signaling that the state should be evolved or a Right
,
signaling that the process can be short-circuited and
the result returned immediately
the result of inserting op
between consecutive
elements of this iterant, going from left to right with
the seed
as the start value, or seed
if the iterant
is empty
Iterant.foldWhileLeftL for the strict version.
Left associative fold using the function op
that can be
short-circuited.
Left associative fold using the function op
that can be
short-circuited.
On execution the stream will be traversed from left to right,
and the given function will be called with the prior result,
accumulating state either until the end, or until op
returns
a Right
result, when the summary is returned.
Example:
import monix.eval.Task // Sums first 10 items Iterant[Task].range(0, 1000).foldWhileLeftL((0, 0)) { case ((sum, count), e) => val next = (sum + e, count + 1) if (count + 1 < 10) Left(next) else Right(next) } // Implements exists(predicate) Iterant[Task].of(1, 2, 3, 4, 5).foldWhileLeftL(false) { (default, e) => if (e == 3) Right(true) else Left(default) } // Implements forall(predicate) Iterant[Task].of(1, 2, 3, 4, 5).foldWhileLeftL(true) { (default, e) => if (e != 3) Right(false) else Left(default) }
is the start value
is the binary operator returning either Left
,
signaling that the state should be evolved or a Right
,
signaling that the process can be short-circuited and
the result returned immediately
the result of inserting op
between consecutive
elements of this iterant, going from left to right with
the seed
as the start value, or seed
if the iterant
is empty
Iterant.foldWhileLeftL for the lazy, potentially asynchronous version.
Returns true
in case the given predicate is satisfied by all
of the emitted items, or false
in case the given predicate
fails for any of those items.
Returns true
in case the given predicate is satisfied by all
of the emitted items, or false
in case the given predicate
fails for any of those items.
Example:
import monix.eval.Coeval val source = Iterant[Coeval].of(1, 2, 3, 4) // Yields false source.forallL(_ % 2 == 0) // Yields true source.existsL(_ < 10)
is a predicate function that's going to test each item emitted by the source until we get a negative match for one of them or until the stream ends
true
if all of the items satisfy the given predicate
or false
if any of them don't
Consumes the source iterable, executing the given callback for each element.
Consumes the source iterable, executing the given callback for each element.
Example:
import monix.eval.Task // Prints all elements, each one on a different line Iterant[Task].of(1, 2, 3).foreach { elem => println("Elem: " + elem.toString) }
is the callback to call for each element emitted by the source.
Given a routine make sure to execute it whenever the current stream reaches the end, successfully, in error, or canceled.
Given a routine make sure to execute it whenever the current stream reaches the end, successfully, in error, or canceled.
Implements cats.effect.Bracket.guarantee
.
Example:
import monix.eval.Task def iterant: Iterant[Task, Int] = Iterant.delay(???) iterant.guarantee(Task.eval { println("Releasing resources!") })
is the function to execute on early stop
Returns a new iterant in which f
is scheduled to be executed
on halt or if canceled.
Returns a new iterant in which f
is scheduled to be executed
on halt or if canceled.
Implements cats.effect.Bracket.guaranteeCase
.
This would typically be used to ensure that a finalizer will run at the end of the stream.
Example:
import monix.eval.Task import cats.effect.ExitCase def iterant: Iterant[Task, Int] = Iterant.delay(???) iterant.guaranteeCase(err => Task.eval { err match { case ExitCase.Completed => println("Completed successfully!") case ExitCase.Error(e) => e.printStackTrace() case ExitCase.Canceled => println("Was stopped early!") } })
is the finalizer to execute when streaming is terminated, by successful completion, error or cancellation
Optionally selects the first element.
Optionally selects the first element.
import monix.eval.Task // Yields Some(1) Iterant[Task].of(1, 2, 3, 4).headOptionL // Yields None Iterant[Task].empty[Int].headOptionL
the first element of this iterant if it is nonempty, or
None
if it is empty, in the F
context.
Lazily interleaves two iterants together, starting with the first
element from self
.
Lazily interleaves two iterants together, starting with the first
element from self
.
The length of the result will be the shorter of the two arguments.
Example:
import monix.eval.Task val lh = Iterant[Task].of(11, 12) val rh = Iterant[Task].of(21, 22, 23) // Yields 11, 21, 12, 22 lh.interleave(rh)
is the other iterant to interleave the source with (the right hand side)
Creates a new stream from the source that will emit the start
element
followed by the upstream elements paired with the separator
and lastly the end
element.
Creates a new stream from the source that will emit the start
element
followed by the upstream elements paired with the separator
and lastly the end
element.
import monix.eval.Coeval // Yields '<', 'a', '-', 'b', '>' Iterant[Coeval].of('a', 'b').intersperse('<', '-', '>')
the first element emitted
the separator
the last element emitted
Creates a new stream from the source that will emit a specific separator
between every pair of elements.
Creates a new stream from the source that will emit a specific separator
between every pair of elements.
import monix.eval.Coeval // Yields 1, 0, 2, 0, 3 Iterant[Coeval].of(1, 2, 3).intersperse(0)
the separator
Optionally selects the last element.
Optionally selects the last element.
import monix.eval.Task // Yields Some(4) Iterant[Task].of(1, 2, 3, 4).lastOptionL // Yields None Iterant[Task].empty[Int].lastOptionL
the last element of this iterant if it is nonempty, or
None
if it is empty, in the F
context.
Returns a new stream by mapping the supplied function over the elements of the source.
Returns a new stream by mapping the supplied function over the elements of the source.
import monix.eval.Task // Yields 2, 4, 6 Iterant[Task].of(1, 2, 3).map(_ * 2)
is the mapping function that transforms the source
a new iterant that's the result of mapping the given function over the source
Returns a new stream by mapping the supplied function over the
elements of the source yielding Iterant
consisting of NextBatch
nodes.
Returns a new stream by mapping the supplied function over the
elements of the source yielding Iterant
consisting of NextBatch
nodes.
import monix.eval.Task import monix.tail.batches.Batch // Yields 1, 2, 3, 4, 5 Iterant[Task].of(List(1, 2, 3), List(4), List(5)).mapBatch(Batch.fromSeq(_)) // Yields 2, 4, 6 Iterant[Task].of(1, 2, 3).mapBatch(x => Batch(x * 2))
is the mapping function that transforms the source into batches.
a new iterant that's the result of mapping the given function over the source
Given a mapping function that returns a possibly lazy or asynchronous result, applies it over the elements emitted by the stream.
Given a mapping function that returns a possibly lazy or asynchronous result, applies it over the elements emitted by the stream.
import monix.eval.Task Iterant[Task].of(1, 2, 3, 4).mapEval { elem => Task.eval { println("Received: " + elem.toString) elem * 2 } }
is the mapping function that transforms the source
a new iterant that's the result of mapping the given function over the source,
Given a functor transformation from F
to G
, lifts the source
into an iterant that is going to use the resulting G
for
evaluation.
Given a functor transformation from F
to G
, lifts the source
into an iterant that is going to use the resulting G
for
evaluation.
This can be used for replacing the underlying F
type into
something else. For example say we have an iterant that uses
monix.eval.Coeval
, but we want to convert it into
one that uses monix.eval.Task
for evaluation:
import cats.~> import monix.eval._ // Source is using Coeval for evaluation val source = Iterant[Coeval].of(1, 2, 3, 4) // Transformation to an Iterant of Task source.mapK(Coeval.liftTo[Task])
This operator can be used for more than transforming the F
type into something else.
is the data type that is going to drive the evaluation of the resulting iterant
is the functor transformation that's used to transform
the source into an iterant that uses G
for evaluation
Takes the elements of the source iterant and emits the element that has the maximum key value, where the key is generated by the given function.
Takes the elements of the source iterant and emits the element that has the maximum key value, where the key is generated by the given function.
Example:
import cats.implicits._ import monix.eval.Coeval case class Person(name: String, age: Int) // Yields Some(Person("Peter", 23)) Iterant[Coeval].of(Person("Peter", 23), Person("May", 21)) .maxByL(_.age) // Yields None Iterant[Coeval].empty[Person].maxByL(_.age)
Monix prefers to work with cats.Order for assessing the order of elements that have an ordering defined, instead of scala.math.Ordering.
We do this for consistency, as Monix is now building on top of Cats. This may change in the future, depending on what happens with typelevel/cats#2455.
Building a cats.Order
is easy to do if you already have a
Scala Ordering
instance:
import cats.Order case class Person(name: String, age: Int) // Starting from a Scala Ordering implicit val scalaOrderingForPerson: Ordering[Person] = new Ordering[Person] { def compare(x: Person, y: Person): Int = x.age.compareTo(y.age) match { case 0 => x.name.compareTo(y.name) case o => o } } // Building a cats.Order from it implicit val catsOrderForPerson: Order[Person] = Order.fromOrdering
You can also do that in reverse, so you can prefer cats.Order
(due to Cats also exposing laws and tests for free) and build a
Scala Ordering
when needed:
val scalaOrdering = catsOrderForPerson.toOrdering
is the function that returns the key for which the given ordering is defined
is the cats.Order
type class instance that's going
to be used for comparing elements
the maximum element of the source stream, relative to its key generated by the given function and the given ordering
Given a cats.Order
over the stream's elements, returns the
maximum element in the stream.
Given a cats.Order
over the stream's elements, returns the
maximum element in the stream.
Example:
import cats.implicits._ import monix.eval.Coeval // Yields Some(20) Iterant[Coeval].of(1, 10, 7, 6, 8, 20, 3, 5).maxL // Yields None Iterant[Coeval].empty[Int].maxL
Monix prefers to work with cats.Order for assessing the order of elements that have an ordering defined, instead of scala.math.Ordering.
We do this for consistency, as Monix is now building on top of Cats. This may change in the future, depending on what happens with typelevel/cats#2455.
Building a cats.Order
is easy to do if you already have a
Scala Ordering
instance:
import cats.Order case class Person(name: String, age: Int) // Starting from a Scala Ordering implicit val scalaOrderingForPerson: Ordering[Person] = new Ordering[Person] { def compare(x: Person, y: Person): Int = x.age.compareTo(y.age) match { case 0 => x.name.compareTo(y.name) case o => o } } // Building a cats.Order from it implicit val catsOrderForPerson: Order[Person] = Order.fromOrdering
You can also do that in reverse, so you can prefer cats.Order
(due to Cats also exposing laws and tests for free) and build a
Scala Ordering
when needed:
val scalaOrdering = catsOrderForPerson.toOrdering
is the cats.Order
type class instance that's going
to be used for comparing elements
the maximum element of the source stream, relative
to the defined Order
Takes the elements of the source iterant and emits the element that has the minimum key value, where the key is generated by the given function.
Takes the elements of the source iterant and emits the element that has the minimum key value, where the key is generated by the given function.
Example:
import cats.implicits._ import monix.eval.Coeval case class Person(name: String, age: Int) // Yields Some(Person("May", 21)) Iterant[Coeval].of(Person("Peter", 23), Person("May", 21)) .minByL(_.age) // Yields None Iterant[Coeval].empty[Person].minByL(_.age)
Monix prefers to work with cats.Order for assessing the order of elements that have an ordering defined, instead of scala.math.Ordering.
We do this for consistency, as Monix is now building on top of Cats. This may change in the future, depending on what happens with typelevel/cats#2455.
Building a cats.Order
is easy to do if you already have a
Scala Ordering
instance:
import cats.Order case class Person(name: String, age: Int) // Starting from a Scala Ordering implicit val scalaOrderingForPerson: Ordering[Person] = new Ordering[Person] { def compare(x: Person, y: Person): Int = x.age.compareTo(y.age) match { case 0 => x.name.compareTo(y.name) case o => o } } // Building a cats.Order from it implicit val catsOrderForPerson: Order[Person] = Order.fromOrdering
You can also do that in reverse, so you can prefer cats.Order
(due to Cats also exposing laws and tests for free) and build a
Scala Ordering
when needed:
val scalaOrdering = catsOrderForPerson.toOrdering
is the function that returns the key for which the given ordering is defined
is the cats.Order
type class instance that's going
to be used for comparing elements
the minimum element of the source stream, relative to its key generated by the given function and the given ordering
Given a cats.Order
over the stream's elements, returns the
minimum element in the stream.
Given a cats.Order
over the stream's elements, returns the
minimum element in the stream.
Example:
import cats.implicits._ import monix.eval.Coeval // Yields Some(3) Iterant[Coeval].of(10, 7, 6, 8, 20, 3, 5).minL // Yields None Iterant[Coeval].empty[Int].minL
Monix prefers to work with cats.Order for assessing the order of elements that have an ordering defined, instead of scala.math.Ordering.
We do this for consistency, as Monix is now building on top of Cats. This may change in the future, depending on what happens with typelevel/cats#2455.
Building a cats.Order
is easy to do if you already have a
Scala Ordering
instance:
import cats.Order case class Person(name: String, age: Int) // Starting from a Scala Ordering implicit val scalaOrderingForPerson: Ordering[Person] = new Ordering[Person] { def compare(x: Person, y: Person): Int = x.age.compareTo(y.age) match { case 0 => x.name.compareTo(y.name) case o => o } } // Building a cats.Order from it implicit val catsOrderForPerson: Order[Person] = Order.fromOrdering
You can also do that in reverse, so you can prefer cats.Order
(due to Cats also exposing laws and tests for free) and build a
Scala Ordering
when needed:
val scalaOrdering = catsOrderForPerson.toOrdering
is the cats.Order
type class instance that's going
to be used for comparing elements
the minimum element of the source stream, relative
to the defined Order
Returns an Iterant
that mirrors the behavior of the source,
unless the source is terminated with an error, in which
case the streaming of events fallbacks to an iterant
emitting a single element generated by the backup function.
Returns an Iterant
that mirrors the behavior of the source,
unless the source is terminated with an error, in which
case the streaming of events fallbacks to an iterant
emitting a single element generated by the backup function.
Example:
import monix.eval.Task import monix.execution.exceptions.DummyException val prefix = Iterant[Task].of(1, 2, 3, 4) val suffix = Iterant[Task].raiseError[Int](DummyException("dummy")) val fa = prefix ++ suffix fa.onErrorHandle { _ => 5 }
See onErrorRecover for the version that takes a partial function as a parameter.
is a function that matches errors with a backup element that is emitted when the source throws an error.
Returns an Iterant
that mirrors the behavior of the source,
unless the source is terminated with an error, in which case
the streaming of events continues with the specified backup
sequence generated by the given function.
Returns an Iterant
that mirrors the behavior of the source,
unless the source is terminated with an error, in which case
the streaming of events continues with the specified backup
sequence generated by the given function.
Example:
import monix.eval.Task import monix.execution.exceptions.DummyException val prefix = Iterant[Task].of(1, 2, 3, 4) val suffix = Iterant[Task].raiseError[Int](DummyException("dummy")) val fa = prefix ++ suffix fa.onErrorHandleWith { case _: DummyException => Iterant[Task].pure(5) case other => Iterant[Task].raiseError[Int](other) }
See onErrorRecoverWith for the version that takes a partial function as a parameter.
is a function that matches errors with a backup throwable that is subscribed when the source throws an error.
Returns a new Iterant
that mirrors the source, but ignores
any errors in case they happen.
Returns an Iterant
that mirrors the behavior of the source,
unless the source is terminated with an error, in which
case the streaming of events fallbacks to an iterant
emitting a single element generated by the backup function.
Returns an Iterant
that mirrors the behavior of the source,
unless the source is terminated with an error, in which
case the streaming of events fallbacks to an iterant
emitting a single element generated by the backup function.
The created Iterant
mirrors the behavior of the source
in case the source does not end with an error or if the
thrown Throwable
is not matched.
Example:
import monix.eval.Task import monix.execution.exceptions.DummyException val prefix = Iterant[Task].of(1, 2, 3, 4) val suffix = Iterant[Task].raiseError[Int](DummyException("dummy")) val fa = prefix ++ suffix fa.onErrorRecover { case _: DummyException => 5 }
See onErrorHandle for the version that takes a total function as a parameter.
- a function that matches errors with a backup element that is emitted when the source throws an error.
Returns an Iterant
that mirrors the behavior of the source,
unless the source is terminated with an error, in which case
the streaming of events continues with the specified backup
sequence generated by the given partial function.
Returns an Iterant
that mirrors the behavior of the source,
unless the source is terminated with an error, in which case
the streaming of events continues with the specified backup
sequence generated by the given partial function.
The created Iterant
mirrors the behavior of the source in
case the source does not end with an error or if the thrown
Throwable
is not matched.
Example:
import monix.eval.Task import monix.execution.exceptions.DummyException val prefix = Iterant[Task].of(1, 2, 3, 4) val suffix = Iterant[Task].raiseError[Int](DummyException("dummy")) val fa = prefix ++ suffix fa.onErrorRecoverWith { case _: DummyException => Iterant[Task].pure(5) }
See onErrorHandleWith for the version that takes a total function as a parameter.
is a function that matches errors with a backup throwable that is subscribed when the source throws an error.
Lazily zip two iterants together, the elements of the emitted tuples being fetched in parallel.
Lazily zip two iterants together, the elements of the emitted tuples being fetched in parallel.
This is the parallel version of zip, the results are still ordered, but it can yield non-deterministic ordering of effects when fetching the elements of an emitted tuple.
is the other iterant to zip the source with (the right hand side)
Lazily zip two iterants together, in parallel, using the given
function f
to produce output values.
Lazily zip two iterants together, in parallel, using the given
function f
to produce output values.
This is like zipMap, except that the element pairs are processed in parallel (ordered results, but non-deterministic ordering of effects).
is the other iterant to zip the source with (the right hand side)
is the mapping function to transform the zipped
(A, B)
elements
Consumes the source by pushing it to the specified channel.
Consumes the source by pushing it to the specified channel.
is a ProducerF value that will be used for consuming the stream
Reduces the elements of the source using the specified associative binary operator, going from left to right, start to finish.
Reduces the elements of the source using the specified associative binary operator, going from left to right, start to finish.
Example:
import monix.eval.Coeval // Yields Some(10) Iterant[Coeval].of(1, 2, 3, 4).reduceL(_ + _) // Yields None Iterant[Coeval].empty[Int].reduceL(_ + _)
is an associative binary operation that's going to be used to reduce the source to a single value
either Some(value)
in case the stream is not empty,
value
being the result of inserting op
between
consecutive elements of this iterant, going from left
to right, or None
in case the stream is empty
Repeats the items emitted by the source continuously
Repeats the items emitted by the source continuously
It terminates either on error or if the source is empty.
Applies a binary operator to a start value and all elements of
this Iterant
, going left to right and returns a new
Iterant
that emits on each step the result of the applied
function.
Applies a binary operator to a start value and all elements of
this Iterant
, going left to right and returns a new
Iterant
that emits on each step the result of the applied
function.
Similar to foldLeftL, but emits the state on each step. Useful for modeling finite state machines.
Example showing how state can be evolved and acted upon:
import monix.eval.Task sealed trait State[+A] { def count: Int } case object Init extends State[Nothing] { def count = 0 } case class Current[A](current: A, count: Int) extends State[A] // Whatever... val source = Iterant[Task].range(0, 1000) val scanned = source.scan(Init : State[Int]) { (acc, a) => acc match { case Init => Current(a, 1) case Current(_, count) => Current(a, count + 1) } } scanned .takeWhile(_.count < 10) .collect { case Current(a, _) => a }
is the initial state
is the function that evolves the current state
a new iterant that emits all intermediate states being
resulted from applying function op
scan0 for the version that emits seed element at the beginning
Applies a binary operator to a start value and all elements of
this Iterant
, going left to right and returns a new
Iterant
that emits on each step the result of the applied
function.
Applies a binary operator to a start value and all elements of
this Iterant
, going left to right and returns a new
Iterant
that emits on each step the result of the applied
function.
This is a version of scan that emits seed element at the beginning,
similar to scanLeft
on Scala collections.
Applies a binary operator to a start value and all elements of
this Iterant
, going left to right and returns a new
Iterant
that emits on each step the result of the applied
function.
Applies a binary operator to a start value and all elements of
this Iterant
, going left to right and returns a new
Iterant
that emits on each step the result of the applied
function.
Similar with scan, but this can suspend and evaluate
side effects in the F[_]
context, thus allowing for
asynchronous data processing.
Similar to foldLeftL and foldWhileLeftEvalL, but emits the state on each step. Useful for modeling finite state machines.
Example showing how state can be evolved and acted upon:
import monix.eval.Task sealed trait State[+A] { def count: Int } case object Init extends State[Nothing] { def count = 0 } case class Current[A](current: Option[A], count: Int) extends State[A] // Dummies case class Person(id: Int, name: String, age: Int) def requestPersonDetails(id: Int): Task[Option[Person]] = Task.delay(???) // Whatever val source = Iterant[Task].range(0, 1000) // Initial state val seed = Task.now(Init : State[Person]) val scanned = source.scanEval(seed) { (state, id) => requestPersonDetails(id).map { a => state match { case Init => Current(a, 1) case Current(_, count) => Current(a, count + 1) } } } scanned .takeWhile(_.count < 10) .collect { case Current(Some(a), _) => a }
is the initial state
is the function that evolves the current state
a new iterant that emits all intermediate states being resulted from applying the given function
Applies a binary operator to a start value and all elements of
this Iterant
, going left to right and returns a new
Iterant
that emits on each step the result of the applied
function.
Applies a binary operator to a start value and all elements of
this Iterant
, going left to right and returns a new
Iterant
that emits on each step the result of the applied
function.
This is a version of scanEval that emits seed element at the beginning,
similar to scanLeft
on Scala collections.
Given a mapping function that returns a B
type for which we have
a cats.Monoid instance, returns a new stream that folds the incoming
elements of the sources using the provided Monoid[B].combine
, with the
initial seed being the Monoid[B].empty
value, emitting the generated values
at each step.
Given a mapping function that returns a B
type for which we have
a cats.Monoid instance, returns a new stream that folds the incoming
elements of the sources using the provided Monoid[B].combine
, with the
initial seed being the Monoid[B].empty
value, emitting the generated values
at each step.
Equivalent with scan applied with the given cats.Monoid, so given
our f
mapping function returns a B
, this law holds:
stream.scanMap(f) <-> stream.scan(Monoid[B].empty)(Monoid[B].combine)
Example:
import cats.implicits._ import monix.eval.Task // Yields 2, 6, 12, 20, 30, 42 Iterant[Task].of(1, 2, 3, 4, 5, 6).scanMap(x => x * 2)
is the mapping function applied to every incoming element of this Iterant
before folding using Monoid[B].combine
a new Iterant
that emits all intermediate states being
resulted from applying Monoid[B].combine
function
scanMap0 for the version that emits empty element at the beginning
Given a mapping function that returns a B
type for which we have
a cats.Monoid instance, returns a new stream that folds the incoming
elements of the sources using the provided Monoid[B].combine
, with the
initial seed being the Monoid[B].empty
value, emitting the generated values
at each step.
Given a mapping function that returns a B
type for which we have
a cats.Monoid instance, returns a new stream that folds the incoming
elements of the sources using the provided Monoid[B].combine
, with the
initial seed being the Monoid[B].empty
value, emitting the generated values
at each step.
This is a version of scanMap that emits seed element at the beginning.
Given evidence that type A
has a scala.math.Numeric
implementation,
sums the stream of elements.
Given evidence that type A
has a scala.math.Numeric
implementation,
sums the stream of elements.
An alternative to foldL which does not require any imports and works
in cases cats.Monoid
is not defined for values (e.g. A = Char
)
In case this Iterant is empty, switch to the given backup.
Drops the first element of the source iterant, emitting the rest.
Drops the first element of the source iterant, emitting the rest.
Example:
import monix.eval.Task // Yields 2, 3, 4 Iterant[Task].of(1, 2, 3, 4).tail
a new iterant that upon evaluation will emit all elements of the source, except for the head
Creates a new iterant that upon evaluation will select
the first n
elements from the source and then stop,
in the order they are emitted by the source.
Creates a new iterant that upon evaluation will select
the first n
elements from the source and then stop,
in the order they are emitted by the source.
Example:
import monix.eval.Task // Yields 1, 2, 3 Iterant[Task].of(1, 2, 3, 4, 5, 6).take(3)
is the number of elements to take from this iterant
a new iterant instance that on evaluation will emit
only the first n
elements of this iterant
Takes every n-th element, dropping intermediary elements and returns a new iterant that emits those elements.
Takes every n-th element, dropping intermediary elements and returns a new iterant that emits those elements.
Example:
import monix.eval.Task // Yields 2, 4, 6 Iterant[Task].of(1, 2, 3, 4, 5, 6).takeEveryNth(2) // Yields 1, 2, 3, 4, 5, 6 Iterant[Task].of(1, 2, 3, 4, 5, 6).takeEveryNth(1)
is the sequence number of an element to be taken (must be > 0)
a new iterant instance that on evaluation will return only every n-th element of the source
Creates a new iterable that only emits the last n
elements
emitted by the source.
Creates a new iterable that only emits the last n
elements
emitted by the source.
In case the source triggers an error, then the underlying buffer gets dropped and the error gets emitted immediately.
Example:
import monix.eval.Task // Yields 1, 2, 3 Iterant[Task].of(1, 2, 3, 4, 5, 6).take(3)
is the number of elements to take from the end of the stream.
a new iterant instance that on evaluation will emit the
last n
elements of the source
Takes longest prefix of elements that satisfy the given predicate and returns a new iterant that emits those elements.
Takes longest prefix of elements that satisfy the given predicate and returns a new iterant that emits those elements.
Example:
import monix.eval.Task // Yields 1, 2, 3 Iterant[Task].of(1, 2, 3, 4, 5, 6).takeWhile(_ < 4)
is the function that tests each element, stopping
the streaming on the first false
result
a new iterant instance that on evaluation will all
elements of the source for as long as the given predicate
returns true
, stopping upon the first false
result
Takes longest prefix of elements zipped with their indices that satisfy the given predicate and returns a new iterant that emits those elements.
Takes longest prefix of elements zipped with their indices that satisfy the given predicate and returns a new iterant that emits those elements.
Example:
import monix.eval.Task // Yields 1, 2 Iterant[Task].of(1, 2, 3, 4, 5, 6).takeWhileWithIndex((_, idx) => idx != 2)
is the function that tests each element, stopping
the streaming on the first false
result
a new iterant instance that on evaluation will all
elements of the source for as long as the given predicate
returns true
, stopping upon the first false
result
Converts this Iterant
to a monix.catnap.ChannelF.
Aggregates all elements in a List
and preserves order.
Aggregates all elements in a List
and preserves order.
Example:
import monix.eval.Task // Yields List(1, 2, 3, 4) Iterant[Task].of(1, 2, 3, 4).toListL
Note that this operation is dangerous, since if the iterant is infinite then this operation is non-terminating, the process probably blowing up with an out of memory error sooner or later.
Converts this Iterant
into an org.reactivestreams.Publisher
.
Converts this Iterant
into an org.reactivestreams.Publisher
.
Meant for interoperability with other Reactive Streams
implementations. Also useful because it turns the Iterant
into another data type with a push-based communication protocol
with back-pressure.
Usage sample:
import monix.eval.Task import monix.execution.rstreams.SingleAssignSubscription import org.reactivestreams.{Publisher, Subscriber, Subscription} def sum(source: Publisher[Int], requestSize: Int): Task[Long] = Task.create { (_, cb) => val sub = SingleAssignSubscription() source.subscribe(new Subscriber[Int] { private[this] var requested = 0L private[this] var sum = 0L def onSubscribe(s: Subscription): Unit = { sub := s requested = requestSize s.request(requestSize) } def onNext(t: Int): Unit = { sum += t if (requestSize != Long.MaxValue) requested -= 1 if (requested <= 0) { requested = requestSize sub.request(requestSize) } } def onError(t: Throwable): Unit = cb.onError(t) def onComplete(): Unit = cb.onSuccess(sum) }) // Cancelable that can be used by Task sub } // Needed for `Effect[Task]` import monix.execution.Scheduler.Implicits.global val pub = Iterant[Task].of(1, 2, 3, 4).toReactivePublisher // Yields 10 sum(pub, requestSize = 128)
See the Reactive Streams for details.
Pull the first element out of this Iterant and return it and the rest.
Pull the first element out of this Iterant and return it and the rest. If the returned Option is None, the remainder is always empty.
The value returned is wrapped in Iterant to preserve resource safety, and consumption of the rest must not leak outside of use. The returned Iterant always contains a single element
import cats._, cats.implicits._, cats.effect._ def unconsFold[F[_]: Sync, A: Monoid](iterant: Iterant[F, A]): F[A] = { def go(iterant: Iterant[F, A], acc: A): Iterant[F, A] = iterant.uncons.flatMap { case (None, _) => Iterant.pure(acc) case (Some(a), rest) => go(rest, acc |+| a) } go(iterant, Monoid[A].empty).headOptionL.map(_.getOrElse(Monoid[A].empty)) }
Applies the function to the elements of the source and concatenates the results.
Applies the function to the elements of the source and concatenates the results.
This variant of flatMap is not referentially transparent,
because it tries to apply function f
immediately, in case the
Iterant
is in a NextCursor
or NextBatch
state.
To be used for optimizations, but keep in mind it's unsafe, as its application isn't referentially transparent.
is the function mapping elements from the source to iterants
Explicit covariance operator.
Explicit covariance operator.
The Iterant type isn't covariant in type param A
, because
covariance doesn't play well with a higher-kinded type like
F[_]
. So in case you have an Iterant[F, A]
, but need an
Iterant[F, B]
, knowing that A extends B
, then you can do an
upcast
.
Example:
import monix.eval.Task val source: Iterant[Task, List[Int]] = Iterant.suspend(???) // This will trigger an error because of the invariance: // val sequences: Iterant[Task, Seq[Int]] = source // But this will work just fine: val sequence: Iterant[Task, Seq[Int]] = source.upcast[Seq[Int]]
Lazily zip two iterants together.
Lazily zip two iterants together.
The length of the result will be the shorter of the two arguments.
Example:
import monix.eval.Task val lh = Iterant[Task].of(11, 12, 13, 14) val rh = Iterant[Task].of(21, 22, 23, 24, 25) // Yields (11, 21), (12, 22), (13, 23), (14, 24) lh.zip(rh)
is the other iterant to zip the source with (the right hand side)
Lazily zip two iterants together, using the given function f
to
produce output values.
Lazily zip two iterants together, using the given function f
to
produce output values.
The length of the result will be the shorter of the two arguments.
Example:
import monix.eval.Task val lh = Iterant[Task].of(11, 12, 13, 14) val rh = Iterant[Task].of(21, 22, 23, 24, 25) // Yields 32, 34, 36, 38 lh.zipMap(rh) { (a, b) => a + b }
is the other iterant to zip the source with (the right hand side)
is the mapping function to transform the zipped
(A, B)
elements
Zips the emitted elements of the source with their indices.
Zips the emitted elements of the source with their indices.
The length of the result will be the same as the source.
Example:
import monix.eval.Task val source = Iterant[Task].of("Sunday", "Monday", "Tuesday", "Wednesday") // Yields ("Sunday", 0), ("Monday", 1), ("Tuesday", 2), ("Wednesday", 3) source.zipWithIndex
The
Iterant
is a type that describes lazy, possibly asynchronous streaming of elements using a pull-based protocol.It is similar somewhat in spirit to Scala's own
collection.immutable.Stream
and with Java'sIterable
, except that it is more composable and more flexible due to evaluation being controlled by anF[_]
monadic type that you have to supply (likemonix.eval.Task
,monix.eval.Coeval
orcats.effect.IO
) which will control the evaluation. In other words, thisIterant
type is capable of strict or lazy, synchronous or asynchronous evaluation.Consumption of an
Iterant
happens typically in a loop where the current step represents either a signal that the stream is over, or a (head, rest) pair, very similar in spirit to Scala's standardList
orIterable
.The type is an ADT, meaning a composite of the following types:
head
and arest
representing the rest of the streamNext
for signaling a whole batch of elements by means of a Batch, a type that's similar with Scala'sIterable
, along with therest
of the stream.Next
for signaling a whole strict batch of elements as a traversable BatchCursor, a type that's similar with Scala'sIterator
, along with therest
of the stream.Last(item)
as an optimisation onNext(item, F.pure(Halt(None)), F.unit)
.Parametric Polymorphism
The
Iterant
type accepts as type parameter anF
monadic type that is used to control how evaluation happens. For example you can usemonix.eval.Task
, in which case the streaming can have asynchronous behavior, or you can usemonix.eval.Coeval
in which case it can behave like a normal, synchronousIterable
.As restriction, this
F[_]
type used should be stack safe inmap
andflatMap
, otherwise you might get stack-overflow exceptions. This is why in general the type class required forF
iscats.effect.Sync
.When building instances, type
F[_]
which handles the evaluation needs to be specified upfront. Example:You'll usually pick between
Task
,Coeval
orIO
for your needs.Attribution
This type was inspired by the
Streaming
type in the Typelevel Cats library (later moved to Dogs), originally committed in Cats by Erik Osheim. It was also inspired by other push-based streaming abstractions, like theIteratee
orIAsyncEnumerable
.is the data type that controls evaluation; note that it must be stack-safe in its
map
andflatMap
operationsis the type of the elements produced by this Iterant