Skip to content

Iter

import { pipe } from '@stopcock/fp'
import * as Iter from '@stopcock/fp/iter'

Iter<A> is a lazy Iterable<A>. Operators do no work until a terminal pulls the sequence. Constructors in this module are repeatable; Iter.from reflects the repeatability of the iterable you provide.

Iter has 25 dual operations. See every direct and curried pair in the complete dual-call catalogue.

Iter.from(iterable)
Iter.fromIterator(() => iterator)
Iter.defer(() => iterable)
Iter.empty()
Iter.of(1, 2, 3)
Iter.range(0, 10, 2)
Iter.repeat(value)
Iter.iterate(seed, next)
Iter.unfold(seed, step)

range excludes its end. repeat and iterate are infinite; pair them with a bounded terminal such as take.

The core lazy vocabulary includes:

Iter.map(f)
Iter.filter(predicate)
Iter.filterMap(f)
Iter.flatMap(f)
Iter.flatten
Iter.tap(effect)
Iter.take(count)
Iter.drop(count)
Iter.takeWhile(predicate)
Iter.dropWhile(predicate)
Iter.scan(reducer, initial)
Iter.chunk(size)
Iter.intersperse(separator)
Iter.distinct
Iter.distinctBy(key)
Iter.concat(other)
Iter.zip(other)
Iter.zipWith(other, combine)

Transformations are usable directly or in pipe:

import { pipe } from '@stopcock/fp'
const doubled = Iter.map([1, 2, 3], (value) => value * 2)
const doubledInPipe = pipe(
[1, 2, 3],
Iter.map((value) => value * 2),
)
const result = pipe(
Iter.range(1, Infinity),
Iter.filter((value) => value % 2 === 0),
Iter.map((value) => value * value),
Iter.take(3),
Iter.toArray,
)
// [4, 16, 36]
Iter.toArray(source)
Iter.toArrayInto(source, target)
pipe(source, Iter.toArrayInto(target))
Iter.reduce(source, reducer, initial)
pipe(source, Iter.reduce(reducer, initial))
Iter.forEach(source, effect)
pipe(source, Iter.forEach(effect))
Iter.first(source) // Option<A>
Iter.last(source) // Option<A>
Iter.find(source, predicate) // Option<A>
pipe(source, Iter.find(predicate)) // Option<A>
Iter.some(source, predicate)
pipe(source, Iter.some(predicate))
Iter.every(source, predicate)
pipe(source, Iter.every(predicate))
Iter.count(source)

Partial terminals return Option; absence is never encoded as an ambiguous undefined.

Short-circuiting operations call return() on an upstream iterator when it is still open. This matters for generators that own file handles, cursors, or other resources:

import { pipe } from '@stopcock/fp'
function* rows() {
try {
yield* databaseCursor
} finally {
databaseCursor.close()
}
}
pipe(rows(), Iter.take(10), Iter.toArray)

The finally block runs after the tenth value.