Documentation
¶
Overview ¶
Package stream provides lazy, memoized, persistent sequences.
A Stream is a linked list where each cell's head is eager and tail is lazy, evaluated at most once. Streams are value types externally with shared memoization via internal pointers. If a tail thunk panics, the cell remains unevaluated and future accesses will retry (re-invoking the thunk).
This package supports pure/in-memory sources only. Effectful sources (channels, iterators) are deferred to a future version.
Index ¶
- func Fold[T, R any](s Stream[T], initial R, fn func(R, T) R) R
- type Stream
- func Concat[T any](a, b Stream[T]) Stream[T]
- func FlatMap[T, R any](s Stream[T], fn func(T) Stream[R]) Stream[R]
- func From[T any](ts []T) Stream[T]
- func Generate[T any](seed T, fn func(T) T) Stream[T]
- func Map[T, R any](s Stream[T], fn func(T) R) Stream[R]
- func Of[T any](vs ...T) Stream[T]
- func Paginate[T, S any](seed S, fn func(S) (T, option.Option[S])) Stream[T]
- func Prepend[T any](v T, s Stream[T]) Stream[T]
- func PrependLazy[T any](v T, tail func() Stream[T]) Stream[T]
- func Repeat[T any](v T) Stream[T]
- func Scan[T, R any](s Stream[T], initial R, fn func(R, T) R) Stream[R]
- func Unfold[T, S any](seed S, fn func(S) (T, S, bool)) Stream[T]
- func Zip[A, B any](a Stream[A], b Stream[B]) Stream[pair.Pair[A, B]]
- func (s Stream[T]) Any(fn func(T) bool) bool
- func (s Stream[T]) Collect() []T
- func (s Stream[T]) Convert(fn func(T) T) Stream[T]
- func (s Stream[T]) Drop(n int) Stream[T]
- func (s Stream[T]) DropWhile(fn func(T) bool) Stream[T]
- func (s Stream[T]) Each(fn func(T))
- func (s Stream[T]) Every(fn func(T) bool) bool
- func (s Stream[T]) Find(fn func(T) bool) option.Option[T]
- func (s Stream[T]) First() option.Option[T]
- func (s Stream[T]) IsEmpty() bool
- func (s Stream[T]) KeepIf(fn func(T) bool) Stream[T]
- func (s Stream[T]) None(fn func(T) bool) bool
- func (s Stream[T]) RemoveIf(fn func(T) bool) Stream[T]
- func (s Stream[T]) Seq() iter.Seq[T]
- func (s Stream[T]) Tail() Stream[T]
- func (s Stream[T]) Take(n int) Stream[T]
- func (s Stream[T]) TakeWhile(fn func(T) bool) Stream[T]
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Stream ¶
type Stream[T any] struct { // contains filtered or unexported fields }
Stream is a lazy, memoized, persistent sequence. The zero value is an empty stream.
Head-eager, tail-lazy: when a cell exists, its head is known. Only the tail is deferred and evaluated at most once. Operations like KeepIf eagerly scan to the first match; Map/Convert/TakeWhile eagerly transform the current head. Tail computation is always deferred into a thunk.
Concurrent tail forcing is synchronized and memoized. Multiple goroutines can safely traverse the same stream; each cell's tail thunk executes at most once (on success). Thunk execution occurs outside internal locks — other goroutines block on internal state, not on user callback execution.
Streams are persistent and memoized: multiple references to the same stream share forced cells. Holding a reference to an early cell pins all forced suffix cells reachable from it. From([]T) closures capture subslice views, which can pin the original backing array.
Retry-on-panic: if a tail thunk panics, the cell stays unevaluated and future Tail() calls re-invoke the thunk. Head computation (at construction) is eager and not retryable. Callback purity is assumed for deterministic retry behavior.
Reentrancy constraint: callbacks must not force the same cell being evaluated. This includes indirect paths (e.g., a Map callback that forces the Map result stream). This constraint is inherent to memoized lazy evaluation.
Stream is a value type externally (like Option, Either, Result). Internal pointer enables shared memoization across multiple references.
func FlatMap ¶
FlatMap applies fn to each element of s and concatenates the resulting streams. Head-eager: scans forward to find the first non-empty inner stream. Standalone because Go methods cannot introduce the extra type parameter R. Panics if fn is nil.
func From ¶
From creates a lazy stream from a slice. Each tail closure captures a subslice view of the original — the backing array may be retained until those closures are evaluated or become unreachable.
func Generate ¶
Generate creates an infinite stream: seed, fn(seed), fn(fn(seed)), ... The seed is the first element (eager); subsequent elements apply fn lazily. Panics if fn is nil.
func Map ¶
Map applies fn to each element, returning a stream of a different type. Eagerly transforms the current head; tail transforms are deferred. Standalone because Go methods cannot introduce the extra type parameter R. Panics if fn is nil.
func Paginate ¶
Paginate creates a stream by repeatedly applying a step function to a seed. Each call to fn returns (element, nextSeed). When nextSeed is not-ok, the stream ends after emitting the element. Unlike Unfold, every call to fn produces an element — the Option[S] controls only whether to continue.
Designed for cursor-based pagination where the continuation token is already an option: the step function returns the page and the optional next cursor.
The first step is evaluated eagerly — a panic on the first call fails at construction and is not retryable. Subsequent steps are lazy and retryable.
func Prepend ¶
Prepend returns a stream with v as the head and s as the tail. The tail reference is captured at construction — s itself may contain unevaluated lazy cells, but the link from this cell to s is immediate.
func PrependLazy ¶
PrependLazy returns a stream with v as the head and a lazily-evaluated tail. The tail function is called at most once when the tail is first accessed, consistent with the package's memoized forcing semantics (see Stream type doc). Panics if tail is nil.
func Repeat ¶
Repeat creates an infinite stream where every element is v. Uses a self-referencing cell — O(1) memory regardless of traversal length.
func Scan ¶
Scan reduces a stream like Fold, but returns a stream of all intermediate accumulator values. Includes the initial value as the first element (scanl semantics). Standalone because Go methods cannot introduce the extra type parameter R. Panics if fn is nil.
func Unfold ¶
Unfold creates a stream by repeatedly applying a step function to a seed. Each call to fn returns (element, nextSeed, ok). When ok is false, the stream ends. Unfold is the dual of Fold: Fold consumes a stream to a value, Unfold produces a stream from a value.
The first step is evaluated eagerly — a panic on the first call fails at construction and is not retryable. Subsequent steps are lazy and retryable.
func Zip ¶
Zip returns a stream of pairs from corresponding elements of a and b. Truncates to the shorter stream.
func (Stream[T]) Any ¶
Any returns true if fn returns true for any element. Short-circuits on first match. On an infinite stream with no matching element, this will not terminate. Panics if fn is nil.
func (Stream[T]) Collect ¶
func (s Stream[T]) Collect() []T
Collect materializes the stream into a slice. Requires a finite stream. Returns nil for an empty stream.
func (Stream[T]) Convert ¶
Convert applies fn to each element, returning a stream of results. Eagerly transforms the current head; tail transforms are deferred. Same-type transform — use standalone Map for cross-type mapping. Panics if fn is nil.
func (Stream[T]) Drop ¶
Drop skips the first n elements. Forces skipped cells eagerly. Negative n returns the stream unchanged.
func (Stream[T]) DropWhile ¶
DropWhile skips elements while fn returns true. Forces skipped cells eagerly. On an infinite stream where fn always returns true, this will not terminate. Panics if fn is nil.
func (Stream[T]) Each ¶
func (s Stream[T]) Each(fn func(T))
Each calls fn for every element. Requires a finite stream. Panics if fn is nil.
func (Stream[T]) Every ¶
Every returns true if fn returns true for every element. Returns true for an empty stream (vacuous truth). Short-circuits on first false. On an infinite stream where fn always returns true, this will not terminate. Panics if fn is nil.
func (Stream[T]) Find ¶
Find returns the first element where fn returns true. Short-circuits on match. On an infinite stream with no matching element, this will not terminate. Panics if fn is nil.
func (Stream[T]) KeepIf ¶
KeepIf returns a stream containing only elements where fn returns true. Eagerly scans to the first match (head-eager constraint); the rest is lazy. On an infinite stream with no matching element, this will not terminate. Panics if fn is nil.
func (Stream[T]) None ¶
None returns true if fn returns false for every element. Returns true for an empty stream (vacuous truth). Short-circuits on first true. On an infinite stream where fn always returns false, this will not terminate. Panics if fn is nil.
func (Stream[T]) RemoveIf ¶
RemoveIf returns a stream containing only elements where fn returns false. It is the complement of KeepIf. Panics if fn is nil.
func (Stream[T]) Seq ¶
Seq returns an iter.Seq that yields each element. Bridges to Go's range protocol. The returned closure captures the original stream head. During iteration, the loop variable advances without accumulating additional references, but the closure itself retains the stream root while it exists.
func (Stream[T]) Tail ¶
Tail returns the rest of the stream after the first element. Forces one cell's tail thunk (mutex-guarded, memoized). Returns empty stream if empty.