11.6. Using Stream, a Lazy Version of a List

Problem

You want to use a collection that works like a List but invokes its transformer methods (map, filter, etc.) lazily.

Solution

A Stream is like a List, except that its elements are computed lazily, in a manner similar to how a view creates a lazy version of a collection. Because Stream elements are computed lazily, a Stream can be long ... infinitely long. Like a view, only the elements that are accessed are computed. Other than this behavior, a Stream behaves similar to a List.

Just like a List can be constructed with ::, a Stream can be constructed with the #:: method, using Stream.empty at the end of the expression instead of Nil:

scala> val stream = 1 #:: 2 #:: 3 #:: Stream.empty
stream: scala.collection.immutable.Stream[Int] = Stream(1, ?)

The REPL output shows that the stream begins with the number 1 but uses a ? to denote the end of the stream. This is because the end of the stream hasn’t been evaluated yet.

For example, given a Stream:

scala> val stream = (1 to 100000000).toStream
stream: scala.collection.immutable.Stream[Int] = Stream(1, ?)

you can attempt to access the head and tail of the stream. The head is returned immediately:

scala> stream.head
res0: Int = 1

but the tail isn’t evaluated yet:

scala> stream.tail
res1: scala.collection.immutable.Stream[Int] = Stream(2, ?)

The ? symbol is the way a lazy collection shows that the end of the collection hasn’t been evaluated yet.

As discussed in Recipe 10.24, transformer methods are computed ...

Get Scala Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.