std/iter
Lazy iteration over any Iter<T>.
The lazy adapters (map, filter, take, flat_map, …) are
type functions on Iter — Iter.map(xs, f) — not protocol
requirements. Each returns Iter<...> backed by a private Seq — a source
expressed as nothing but its own push loop — so chains stay lazy,
consuming one element at a time through the whole pipeline without building
intermediate lists. There are no eager, container-preserving adapter functions
on the collections: to get a container back, append an explicit materialize
step — Iter.map(xs, f) |> Iter.to_list(),
Iter.filter(s, p) |> Iter.to_set().
The terminals are also type functions on Iter —
Iter.reduce(xs, f) — over any Iter<T>. The Iter interface itself is
just the { each_while, known_count } protocol. Terminals come in two kinds:
- Streaming:
reduce,each,find,any?,all?,empty?produce a scalar; no concrete collection is ever built. - Materializing:
to_list/to_set/sort, plusto_map/to_string, consume the iterator and produce a concrete collection.
A collection’s own form of an op may diverge from the generic one
(String.reverse → String rebuilds a String, not the generic
List), so those collections keep a container-specific native function;
the generic form (Iter.reverse -> List) stays an Iter type function.
Infinite sequences: Iter.from(0) / Iter.iterate(seed, step) /
Iter.repeat(x) / Iter.cycle(xs) produce iterators that don’t
terminate on their own. Bound them with Iter.take(n) or
Iter.take_while(pred) before a materializing terminal, or use
short-circuiting terminals like Iter.find / Iter.any?.
If you want a List back from a List, the spelling is always the explicit
Iter.map(xs, f) |> Iter.to_list() — the lazy adapter plus a materialize
step. There is no eager List.map; the materialize step is what makes the
result strict.
Iterables in Nomi are replayable: binding x = Iter.map(xs, f) and
consuming x multiple times yields consistent results, because a source
walks itself from a value it never mutates.
Iter also hosts loop, the state-threading repetition primitive —
it takes no collection, but its callback speaks the same break/continue
protocol as every other iteration callback here.
Import with import std/iter.
Exports
Section titled “Exports”Interfaces
interface Iter
Section titled “interface Iter”interface Iter<T> { fn each_while(collection: self, yield: (T) -> Bool): Bool fn known_count(collection: self): Maybe<Int> }
Protocol for pushing elements to a consumer.
A type implementing Iter<T> provides a single function, each_while,
that walks its own elements and hands each one to yield. Returning False
from yield asks the source to stop; each_while itself returns True
when the source ran to exhaustion and False when a consumer stopped it
early. The source drives its own loop, so no self appears anywhere in the
signature and nothing is rebuilt per element. This is Go’s iter.Seq shape,
spelled for Nomi.
Because each_while reads a collection it never mutates, Nomi iterators are
replayable — driving the same iterator binding twice yields the same
sequence.
Built-in types like List, Map, String, and ranges over Discrete
values (Int, Codepoint) already implement Iter, so the operations
below work directly on them. To implement it for a custom type, walk your
own structure and stop as soon as yield says to:
pub struct Countdown { from: Int } impl Iter for Countdown { fn each_while(c: Countdown, yield: (Int) -> Bool): Bool { if c.from <= 0 { True } else { if yield(c.from) { each_while(Countdown{from: c.from - 1}, yield) } else { False } } } }
Iter.each_while
Section titled “Iter.each_while”fn each_while(collection: self, yield: (T) -> Bool): Bool
interface Iter
Iter.known_count
Section titled “Iter.known_count”fn known_count(collection: self): Maybe<Int>
interface Iter
Iter.loop
Section titled “Iter.loop”fn loop<S>(f: (S) -> S): S
type function on Iter
Loops indefinitely, invoking f each iteration. The callback either
carries state (declare its first parameter with a default — that default
is the initial state, e.g. |n = 0|) or is stateless (|| body). The
callback’s return value becomes the next iteration’s state. The state
type, the break value type, and the loop’s result type are all one
type S: for a stated callback S comes from the default; for a
stateless callback S is inferred from the break value.
Use break value to exit with value, or bare break to exit with
Unit. Without an explicit break this loops forever.
Interactive Tests
assert Iter.loop(|n = 0|
if n >= 3 {
break n
} else {
n + 1
}
) == 3
assert Iter.loop(|| { break 42 }) == 42
Iter.reduce
Section titled “Iter.reduce”fn reduce<T, U>(source: Iter<T>, f: (U, T) -> U): U
type function on Iter
Reduces a collection to a single value by folding.
The initial accumulator is provided by the lambda’s default parameter:
If the lambda has no default (e.g., |a, b| ...), the first element
of the collection is used as the initial accumulator and iteration starts
at the second element. Errors if the collection is empty.
Supports break / break value / continue in the callback.
Interactive Tests
assert Iter.reduce([1, 2, 3], |acc = 0, x| acc + x) == 6
Iter.find
Section titled “Iter.find”fn find<T>(source: Iter<T>, f: (T) -> Bool): Maybe<T>
type function on Iter
Returns the first element matching the predicate, or None.
Interactive Tests
assert Iter.find([1, 2, 3, 4], |x| x > 2) == Some(3)
assert Iter.find([1, 2], |x| x > 99) == None
Iter.sort_with
Section titled “Iter.sort_with”fn sort_with<T>(source: Iter<T>, compare: (T, T) -> Ordering): List<T>
type function on Iter
Consumes the iterator and returns its elements as a List sorted by the
comparator. A materializing terminal — like to_list, but ordered — so
it works on any iterable (a lazy chain, a range, a List). The sort is
stable: equal elements keep their input order.
This is the explicit-comparator sort primitive (no Comparable bound).
When the element type is Comparable, prefer sort (natural order) or
sort_by (key projection), which call this under the hood.
Interactive Tests
assert Iter.sort_with([3, 1, 2], Int.compare) == [1, 2, 3]
Iter.sort
Section titled “Iter.sort”fn sort<T>(source: Iter<T>, direction: Direction): List<T> where T: Comparable
type function on Iter
Consumes the iterator and returns its elements as a List in natural
order, using the element type’s Comparable impl. Defaults to ascending;
pass Descending to flip. A materializing terminal — works on any
iterable (a lazy chain, a Range, a List). The sort is stable: equal
elements keep their input order.
Interactive Tests
assert Iter.sort([3, 1, 2]) == [1, 2, 3]
assert Iter.sort([3, 1, 2], Direction.Descending) == [3, 2, 1]
Iter.sort_by
Section titled “Iter.sort_by”fn sort_by<T, K>(source: Iter<T>, direction: Direction, key: (T) -> K): List<T> where K: Comparable
type function on Iter
Sorts by a Comparable key projected from each element, returning a List
in key order. Defaults to ascending; pass Descending to flip. A
materializing terminal; the sort is stable. The trailing key lambda may
be passed with direction omitted (Iter.sort_by(xs, |x| x.k)); the
default fills the skipped slot.
Interactive Tests
assert Iter.sort_by(["bb", "a", "ccc"], |s| String.length(s)) == [
"a",
"bb",
"ccc",
]
assert Iter.sort_by([1, 2, 3], Direction.Descending, |n| n) == [3, 2, 1]
Iter.each
Section titled “Iter.each”fn each<T>(source: Iter<T>, f: (T) -> Unit): Unit
type function on Iter
Calls f for each element. Returns Unit (discards the accumulator).
Interactive Tests
seen = Iter.reduce([1, 2, 3], |acc = 0, n| acc + n)
assert seen == 6
assert Iter.each([1, 2, 3], |_n| Unit) == Unit
Iter.any?
Section titled “Iter.any?”fn any?<T>(source: Iter<T>, f: (T) -> Bool): Bool
type function on Iter
Returns true if any element matches the predicate. Short-circuits on the first match.
Interactive Tests
assert Iter.any?([1, 2, 3], |x| x > 2)
refute Iter.any?([1, 2], |x| x > 99)
Iter.all?
Section titled “Iter.all?”fn all?<T>(source: Iter<T>, f: (T) -> Bool): Bool
type function on Iter
Returns true if all elements match the predicate. Vacuously true for an empty iterator. Short-circuits on the first miss.
Interactive Tests
assert Iter.all?([2, 4, 6], |x| x > 0)
refute Iter.all?([2, -4, 6], |x| x > 0)
Iter.empty?
Section titled “Iter.empty?”fn empty?<T>(source: Iter<T>): Bool
type function on Iter
Returns true if the iterator is empty. Short-circuits on the first element.
Interactive Tests
assert Iter.empty?([])
refute Iter.empty?([1])
Iter.not_empty?
Section titled “Iter.not_empty?”fn not_empty?<T>(source: Iter<T>): Bool
type function on Iter
Returns true if the iterator has at least one element. Short-circuits.
Interactive Tests
assert Iter.not_empty?([1])
refute Iter.not_empty?([])
Iter.first
Section titled “Iter.first”fn first<T>(source: Iter<T>): Maybe<T>
type function on Iter
Returns the first element, or None if the iterator is empty. Terminal;
short-circuits after one step. (List spells this head, paired with
tail — the cons-list idiom; first is the stream-vocabulary name that
every iterator shares.)
Interactive Tests
assert Iter.first([1, 2, 3]) == Some(1)
assert Iter.first([]) == None
Iter.last
Section titled “Iter.last”fn last<T>(source: Iter<T>): Maybe<T>
type function on Iter
Returns the last element, or None if the iterator is empty. Terminal; consumes the whole iterator (does not terminate on an infinite source).
Interactive Tests
assert Iter.last([1, 2, 3]) == Some(3)
assert Iter.last([]) == None
Iter.at
Section titled “Iter.at”fn at<T>(source: Iter<T>, index: Int): Maybe<T>
type function on Iter
Returns the element at the given zero-based index, or None if the index is out of range (or negative). Walks the iterator, so it’s O(index).
Interactive Tests
assert Iter.at([10, 20, 30], 1) == Some(20)
assert Iter.at([10, 20, 30], 9) == None
assert Iter.at([10, 20, 30], -1) == None
Iter.partition
Section titled “Iter.partition”fn partition<T>(source: Iter<T>, f: (T) -> Bool): (List<T>, List<T>)
type function on Iter
Splits the elements into (matches, rest) by a predicate, preserving the original order within each. Materializing.
Interactive Tests
assert Iter.partition([1, 2, 3, 4], |x| x > 2) == ([3, 4], [1, 2])
Iter.group_by
Section titled “Iter.group_by”fn group_by<T, K>(source: Iter<T>, key_fn: (T) -> K): Map<K, List<T>>
type function on Iter
Groups elements by a key function. Each group preserves the original order of its members. Materializing.
Interactive Tests
assert Iter.group_by([1, 2, 3, 4], |x| x % 2) == {1 => [1, 3], 0 => [2, 4]}
Iter.to_list
Section titled “Iter.to_list”fn to_list<T>(source: Iter<T>): List<T>
type function on Iter
Consumes the iterator and materializes its elements into a List. A List
argument is returned as-is (O(1) — lists are immutable); any other iterator
is folded into a fresh List.
Interactive Tests
assert Iter.from(0) |> Iter.take(3) |> Iter.to_list() == [0, 1, 2]
Iter.to_set
Section titled “Iter.to_set”fn to_set<T>(source: Iter<T>): Set<T>
type function on Iter
Consumes the iterator and materializes its elements into a Set, discarding duplicates.
Interactive Tests
assert Iter.to_set([1, 2, 2, 3]) == #{1, 2, 3}
Iter.with_index
Section titled “Iter.with_index”fn with_index<T>(source: Iter<T>): Iter<(Int, T)>
type function on Iter
Lazy: pairs each element of source with a zero-based index.
Interactive Tests
assert ["a", "b", "c"] |> Iter.with_index() |> Iter.to_list() == [
(0, "a"),
(1, "b"),
(2, "c"),
]
Iter.take
Section titled “Iter.take”fn take<T>(source: Iter<T>, n: Int): Iter<T>
type function on Iter
Lazy: yields at most the first n elements of source. Useful for bounding
an infinite iterator.
Interactive Tests
assert Iter.from(0) |> Iter.take(3) |> Iter.to_list() == [0, 1, 2]
Iter.cycle
Section titled “Iter.cycle”fn cycle<T>(source: Iter<T>): Iter<T>
type function on Iter
Lazy: cycles through source endlessly. Empty source yields nothing.
Interactive Tests
assert [1, 2, 3]
|> Iter.cycle()
|> Iter.take(7)
|> Iter.to_list() == [1, 2, 3, 1, 2, 3, 1]
Iter.concat
Section titled “Iter.concat”fn concat<T>(a: Iter<T>, b: Iter<T>): Iter<T>
type function on Iter
Lazy: yields all elements of a, then all of b.
Interactive Tests
assert Iter.concat([1, 2], [3, 4]) |> Iter.to_list() == [1, 2, 3, 4]
Iter.zip
Section titled “Iter.zip”fn zip<T, U>(a: Iter<T>, b: Iter<U>): Iter<(T, U)>
type function on Iter
Lazy: pairs elements from two iterators. Stops when either exhausts.
Interactive Tests
assert Iter.zip([1, 2, 3], ["a", "b"]) |> Iter.to_list() == [(1, "a"), (2, "b")]
Iter.take_while
Section titled “Iter.take_while”fn take_while<T>(source: Iter<T>, pred: (T) -> Bool): Iter<T>
type function on Iter
Lazy: yields elements of source while pred returns true. In the callback,
value is the keep/stop decision: break True takes the current element
then stops, break False/bare break stop without it, continue skips it.
Interactive Tests
assert Iter.from(1)
|> Iter.take_while(|x| x < 4)
|> Iter.to_list() == [1, 2, 3]
Iter.map
Section titled “Iter.map”fn map<T, U>(source: Iter<T>, f: (T) -> U): Iter<U>
type function on Iter
Lazy: applies f to each element of source.
Interactive Tests
assert [1, 2, 3] |> Iter.map(|x| x * 10) |> Iter.to_list() == [10, 20, 30]
Iter.filter
Section titled “Iter.filter”fn filter<T>(source: Iter<T>, pred: (T) -> Bool): Iter<T>
type function on Iter
Lazy: keeps only elements where pred returns true. In the callback,
value is the keep/drop decision: break True keeps the current element
then stops, break False drops it then stops, bare break stops without
deciding, continue skips. Append |> Iter.to_list() for the strict,
List-returning form.
Interactive Tests
assert [1, 2, 3, 4] |> Iter.filter(|x| x > 2) |> Iter.to_list() == [3, 4]
Iter.drop
Section titled “Iter.drop”fn drop<T>(source: Iter<T>, n: Int): Iter<T>
type function on Iter
Lazy: skips the first n elements of source.
Interactive Tests
assert [1, 2, 3, 4] |> Iter.drop(2) |> Iter.to_list() == [3, 4]
Iter.drop_while
Section titled “Iter.drop_while”fn drop_while<T>(source: Iter<T>, pred: (T) -> Bool): Iter<T>
type function on Iter
Lazy: drops the leading run of elements where pred is true.
Interactive Tests
assert [1, 2, 3, 1] |> Iter.drop_while(|x| x < 3) |> Iter.to_list() == [3, 1]
Iter.flat_map
Section titled “Iter.flat_map”fn flat_map<T, U>(source: Iter<T>, f: (T) -> Iter<U>): Iter<U>
type function on Iter
Lazy: for each element of source, apply f and yield all its elements.
Interactive Tests
assert [1, 2, 3]
|> Iter.flat_map(|x| [x, x * 10])
|> Iter.to_list()
|> List.equal?([1, 10, 2, 20, 3, 30])
Iter.chunks
Section titled “Iter.chunks”fn chunks<T>(source: Iter<T>, size: Int): Iter<List<T>>
type function on Iter
Lazy: yields adjacent fixed-size chunks as Lists. The final chunk may be shorter. A non-positive size yields no chunks.
Interactive Tests
assert [1, 2, 3, 4, 5] |> Iter.chunks(2) |> Iter.to_list() == [
[1, 2],
[3, 4],
[5],
]
Iter.chunk_by
Section titled “Iter.chunk_by”fn chunk_by<T, K>(source: Iter<T>, key_fn: (T) -> K): Iter<List<T>> where K: Equatable
type function on Iter
Lazy: yields adjacent runs whose elements produce equal keys. Unlike
group_by, this never reorders or merges non-adjacent elements.
Interactive Tests
assert [1, 1, 2, 2, 1] |> Iter.chunk_by(|x| x) |> Iter.to_list() == [
[1, 1],
[2, 2],
[1],
]
assert ["ant", "ape", "bee", "bat", "cat"]
|> Iter.chunk_by(|s| String.contains?(s, "a"))
|> Iter.to_list()
|> List.equal?([["ant", "ape"], ["bee"], ["bat", "cat"]])
Iter.from
Section titled “Iter.from”fn from(start: Int): Iter<Int>
type function on Iter
Infinite iterator yielding start, start+1, start+2, …
Interactive Tests
assert Iter.from(10) |> Iter.take(3) |> Iter.to_list() == [10, 11, 12]
Iter.repeat
Section titled “Iter.repeat”fn repeat<T>(x: T): Iter<T>
type function on Iter
Infinite iterator yielding x forever.
Interactive Tests
assert Iter.repeat("ha") |> Iter.take(3) |> Iter.to_list() == ["ha", "ha", "ha"]
Iter.iterate
Section titled “Iter.iterate”fn iterate<T>(seed: T, step: (T) -> T): Iter<T>
type function on Iter
Infinite iterator: seed, step(seed), step(step(seed)), …
The step callback runs in iter-callback context:
- Plain return value v: emit the current state, advance to v.
break v: emit v as the final element, then stop.- bare
break: stop immediately without emitting. continue: runtime error — iterate’s step is the state-advancement, socontinuehas no next state to fall forward to. UseIter.iterate(...) |> Iter.filter(...)to skip states.
Interactive Tests
assert Iter.iterate(1, |x| x * 2)
|> Iter.take(4)
|> Iter.to_list() == [1, 2, 4, 8]
assert Iter.iterate(0, |n|
if n > 5 {
break n
} else {
n + 1
}
)
|> Iter.to_list()
|> List.equal?([0, 1, 2, 3, 4, 5, 6])
Iter.to_map
Section titled “Iter.to_map”fn to_map<K, V>(source: Iter<(K, V)>): Map<K, V>
type function on Iter
Consumes the iterator and materializes its (K, V) pair elements into a Map. Runtime error if elements aren’t pairs.
Stays a Go extern: it keeps the pair-element-type constraint error at the
builtin boundary, and avoids iter reaching for std/maps.
Interactive Tests
assert Iter.to_map([("a", 1), ("b", 2)]) == {"a" => 1, "b" => 2}
Iter.to_string
Section titled “Iter.to_string”fn to_string(source: Iter<String>): String
type function on Iter
Consumes the iterator and concatenates its string elements. Runtime error if elements aren’t strings.
Interactive Tests
assert Iter.to_string(["he", "llo"]) == "hello"
Iter.flatten
Section titled “Iter.flatten”fn flatten<U>(source: Iter<Iter<U>>): List<U>
type function on Iter
Flattens an iterator of iterators into a single List, preserving order. Like
to_map/to_string, its source has a specific element shape — the elements
must themselves be iterable — so it’s a type function rather than a
self-based Iter interface function.
Interactive Tests
assert Iter.flatten([[1, 2], [3], [4, 5]]) == [1, 2, 3, 4, 5]
Iter.reverse
Section titled “Iter.reverse”fn reverse<T>(source: Iter<T>): List<T>
type function on Iter
Returns the elements of source reversed, as a List. A materializing
terminal (consumes the whole iterator). Generic over any iterator. A
collection that wants its own container back keeps a container-specific
native function (String.reverse → String), which is why this generic form is
a type function rather than an Iter protocol function: the two return types
would otherwise have to diverge, and String.reverse could not equal
Iter.reverse.
Interactive Tests
assert Iter.reverse([1, 2, 3]) == [3, 2, 1]
Iter.count
Section titled “Iter.count”fn count<T>(source: Iter<T>): Int
type function on Iter
Returns the number of elements in source, consuming it. The single
generic count over any Iter<T>: it consults the known_count protocol
function first, so it’s O(1) on any source that stores its size
(List/Map/Set/bounded ranges whose element type can count steps);
everything else (lazy pipelines,
String) inherits the None default and folds in O(n). Because the fold
runs to exhaustion, Iter.count does not terminate on an infinite
source — bound it with Iter.take(n) first. For the sized-only,
non-consuming answer (None when unknown or unbounded), use
Iter.known_count directly.
Interactive Tests
assert Iter.count([10, 20, 30]) == 3
assert Iter.from(0) |> Iter.take(5) |> Iter.count() == 5