Streams and Iterators - Spicery/Nutmeg GitHub Wiki

Streams and iterators are two-sides of the same coin. Both are ways of generating a linear sequence of values. Streams are the declarative version of iterators:

### Iterators are stateful and advance to the next item automatically.
iterator.next() -> T else None

### A stream always returns the same head element. You need to access the tail to get the next elements.
stream.head() -> T else None
stream.tail() -> Stream<T> else None
stream.isEmpty() -> bool
stream.dest() -> (T, Stream<T>) else None

### Streams and iterators can be easily interconverted. Streams are therefore iterable and iterators are streamable.
stream.asIterator() -> Iterator<T>
iterator.asStream() -> Stream<T>

interface Iterator<T>:
    ^next() -> T else None
end

interface Stream<T>:
    ^head() -> T else None
    ^tail() -> Stream<T> else None

    def ^isEmpty():
        try ^head():
        case None: True
        case _: False
        end
    end

    def ^dest() -> _ else None:
        ^head()?
        ^tail()?
    end 
end

New streams can be easily be generated by mapping over streamables, such as a Range.

stream.Map(f)

Both streams and iterators can be expanded, yielding all their values, with the expand function.

>>> println( expand(0..<5) )
01234