If The first cell stores ; its lazily memoized successor stores ; the next stores , and so on. A cell's successor is evaluated at most once. The representation invariant is that each cursor points to the cell holding its next result.
f is a pure function on immutable values, a simple implementation stores the next value and copies it into a fresh FunIter. Part (d)'s suggested mutable programming closure, however, would be shared by such copies and violate independence. A memoized iterator snapshot avoids that contradiction: all cursors share already determined sequence values, but each has its own position.class FunIter[T](v: T, f: T => T) extends Iter[T] {
private class Cell(val head: T) {
lazy val tail: Cell = new Cell(f(head))
}
private class Cursor(private var cell: Cell) extends Iter[T] {
def hasNext: Boolean = true
def next(): T = {
val answer = cell.head
cell = cell.tail
answer
}
def copy(): Iter[T] = new Cursor(cell)
}
private val cursor = new Cursor(new Cell(v))
def hasNext: Boolean = true
def next(): T = cursor.next()
def copy(): Iter[T] = cursor.copy()
}next returns that result and advances only this cursor. copy shares the cell, whose future is memoized, rather than the mutable cursor. Advancing either copy therefore cannot skip entries in the other.Assume each demanded application of f terminates and generated values are immutable for purposes of observation. A stateful generator should be privately owned by this family of cursors; arbitrary external changes to it cannot be made independent by the supplied interface. Unlike the pure-function implementation, memoization can retain a long prefix while one copy lags far behind another. The question imposes no constant-storage requirement.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