Skip to Content
i documentation
Standard library referenceModules

std/stream

Replayable pull streams. Construction is pure; each pull repeats its work with the services at that call. No stream owns or closes a resource: keep the resource scope around consumption, including early termination. Skipping may consume unbounded input in one pull. Searches and folds use tail calls; collection reverses once. Composition chains still add depth. Ordinary equality compares representation, not observations. There is no memoization, fusion guarantee, or implicit cleanup when a value is dropped.

Stream

Stream(A, E, N) = (() <- (Fail(E), ..N) -> Step(A, E, N), (N) -> Nil)

Step

Step(A, E, N) = Done | Next(A, E, N)

new

An empty stream in any chosen common environment.

new = <A, N>() -> Stream(A, Never, N) {

wrap

One item, followed by an empty tail.

wrap = <A, N>(item : A) -> Stream(A, Never, N) {

from_list

Builds one cell per pull, without walking the list at construction.

from_list = <A, N>(items : List(A)) -> Stream(A, Never, N) {

make

Stores a step without calling it. The private marker makes N invariant.

make = <A, E, N>(step : () <- (Fail(E), ..N) -> Step(A, E, N)) -> Stream(

defer

Defers both construction and the first pull until demand.

defer = <A, E, N>(body : () <- (Fail(E), ..N) -> Stream(A, E, N)) -> Stream(

unfold

Calls the state transition once per pull.

unfold = <S, A, E, N>(

pull

Calls the stored step once. Repeated pulls do not cache or advance.

pull = <A, E, N>(stream : Stream(A, E, N)) -> Step(A, E, N) {

map

Transforms only the demanded cell.

map = <A, B, E, F, N>(

filter

Seeks the next retained item using tail calls.

filter = <A, E, F, N>(

filter_map

Seeks the next present mapped item using tail calls.

filter_map = <A, B, E, F, N>(

flat_map

Drains each inner stream before demanding another outer item.

flat_map = <A, B, E, F, G, N>(

append

Exhausts first before pulling second; arguments themselves are strict.

append = <A, E, F, N>(

zip

Pulls left first. An empty left never pulls right.

zip = <A, B, E, F, N>(

take

Nonpositive bounds never pull the source, nor is the kth tail prefetched.

take = <A, E, N>(from : Stream(A, E, N), up_to : Int) -> Stream(A, E, N) {

drop

Skips only on demand; negative counts skip nothing.

drop = <A, E, N>(from : Stream(A, E, N), up_to : Int) -> Stream(A, E, N) {

take_while

Consumes the first rejected item, without pulling its tail.

take_while = <A, E, F, N>(

fold

Consumes in order, passing (accumulator, element).

fold = <A, Acc, E, N>(

fold_until

Stop returns immediately without demanding the tail.

fold_until = <A, Acc, E, N>(

each

Discards callback results; an infinite input may never finish.

each = <A, B, E, N>(over : Stream(A, E, N), with : (A) <- N -> B) -> Nil {

to_list

Collects in order with one reversal, using O(k) space.

to_list = <A, E, N>(stream : Stream(A, E, N)) -> List(A) {

from_results

Raises the first Error when its position is pulled.

from_results = <A, E, N>(items : List(Result(A, E))) -> Stream(A, E, N) {

attempt

Emits one error value on failure and then ends. Does not catch Assert.

attempt = <A, E, N>(stream : Stream(A, E, N)) -> Stream(

map_environment

Runs each input pull through a fixed-result runner, rebuilding every tail.

map_environment = <A, E, N, M>(