Stream

Builtin.Stream(item) :: # (opaque)

An effectful iterator: identical to Iter except that its step! thunk is effectful, so combinators like Stream.map can run effects per item while staying lazy. Produced from an Iter via Iter.stream, or from an effectful source via Stream.custom, and consumed by a for! loop, [Stream.fold!], [Stream.for_each!], or [Stream.collect!].

from_iter : Iter(item) -> Stream(item)

Lift a pure Iter into a Stream. The lifted steps do no effect themselves, but the stream can then be combined with effectful operations like Stream.map. Carries the source's length forward so [Stream.collect!] can pre-size.

custom : state, [Known(U64), Unknown], (state => Try((item, state), [NoMore])) -> Stream(item)

Build a lazy, effectful stream from a seed; the effectful counterpart of Iter.custom. Each pull runs advance! exactly once: Ok((item, next_state)) yields item and continues from next_state, while Err(NoMore) ends the stream. Building the stream runs no effects. Known(n) promises exactly n items; sources whose length is only discovered by reading (files, stdin, sockets) use Unknown. A source that yields more items than its Known count reports Unknown from then on.

Source errors belong in item (e.g. Try(List(U8), ReadErr)). To stop after an error, yield it paired with a terminal state that holds no resource, so the resource is released rather than retained by the rest of the stream.

map : Stream(a), (a => b) -> Stream(b)

Transform each item of this stream. The transform may run effects; because the stream's steps are already effectful, building the mapped stream stays lazy (the transform runs only as the stream is driven).

map! : Stream(a), (a => b) => Stream(b)

Transform each item of this stream with an effectful function.

with_index : Stream(a) -> Stream((U64, a))

Returns a stream that pairs each item with its position among the items this stream yields. The first yielded item gets index 0, and the index only advances for items that are actually yielded.

keep_if : Stream(a), (a => Bool) -> Stream(a)

Returns a stream of only the items for which predicate! returns Bool.True. The predicate may run effects; it runs once per item as the stream is driven.

drop_if : Stream(a), (a => Bool) -> Stream(a)

Returns a stream without the items for which predicate! returns Bool.True. The predicate may run effects; it runs once per item as the stream is driven.

take_first : Stream(item), U64 -> Stream(item)

Returns a stream that yields at most the first n items of this stream. Once n items have been yielded, the source is not pulled again.

drop_first : Stream(item), U64 -> Stream(item)

Returns a stream that skips the first n items of this stream. The skipped items are still pulled from the source, so their effects still run.

stream : Stream(item) -> Stream(item)

Returns this stream unchanged. A for! loop calls stream on the value it loops over, so this is what lets for! consume a Stream directly.

fold! : Stream(a), acc, (acc, a => acc) => acc

Drive the stream to completion, combining its items into one value.

for_each! : Stream(a), (a => {}) => {}

Drive the stream to completion, running f! on each item in order.

next! : Stream(item) => [One({ item : item, rest : Stream(item) }), Skip({ rest : Stream(item) }), Done]

Advance the stream by one step.

size_hint : Stream(item) -> [Known(U64), Unknown]

Returns the stream's length if it is known up front.

collect! : Stream(item) => List(item)

Drive the stream to completion with an explicit loop, collecting its items into a List (pre-sized from len_if_known when known).