Memoized iterator snapshot 2026-10-31
Represent a generated sequence by shared memoized lazy list cells and let each iterator hold its own current cell reference. Copy that reference into a new iterator object. Advancing one cursor changes no other cursor, while every cell's future tail is generated once. Thus even a privately stateful generator can supply identical future values to independently consumed snapshots, provided its state is owned by this shared sequence and not mutated externally. Retained older cursors can keep cached prefixes alive. [ref]
import scala.collection.immutable.Stream
class FunIter[T] private (
private var rest: Stream[T]) extends Iter[T] {
def this(v: T, f: T => T) = this(Stream.iterate(v)(f))
def hasNext: Boolean = true
def next(): T = {
val result = rest.head
rest = rest.tail
result
}
def copy(): Iter[T] = new FunIter[T](rest)
}For a total step function, the stream is infinite and its values are . At every call,
rest starts with the next unconsumed value. Copying that reference gives a new cursor at exactly the same position; later cursor assignments are independent.The memoized iterator snapshot is useful for the next part: if
f owns private mutable state, advancing either cursor realizes a previously unknown tail only once, and both copies can then read the same cached values. Merely constructing new FunIter(current, f) would share the mutable closure while generating two independent futures, which could diverge. Memoization instead makes the generated sequence shared and the consumption positions independent. The closure must not be mutated externally, and generic element payloads are shared rather than deep-copied. Retaining an old cursor can retain cached cells.[ref]Scala 2.12 Stream API documentation. Opening memoization example and notes on retained heads