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>(