LazyList is a Scala sequence whose head and tail are evaluated only when demanded. It can describe finite or infinite sequences, separating the description of a computation from running it. section 5.3 section 5.6
LazyList becomes useful when evaluation should be incremental, reusable, or interruptible:
- A smart cons constructor memoizes by-name head and tail arguments, so each demanded element is computed at most once. section 5.2.1
- Operations such as exists, take, and foldRight can inspect only the demanded prefix and stop early. section 5.3
- An infinite LazyList remains usable when operations consume a finite, productive portion; an always-searching operation may not terminate. section 5.4
An infinite sequence with finite demand
val ones: LazyList[Int] = LazyList.cons(1, ones) ones.take(5).toList // List(1, 1, 1, 1, 1) ones.exists(_ % 2 != 0) // true The recursive definition describes infinitely many values, but take and exists force only enough of the sequence to produce their answers. section 5.4 section 5.6
Listing 5.3 Program trace for LazyList
LazyList(1, 2, 3, 4).map(_ + 10).filter(_ % 2 == 0).toList cons(11, LazyList(2, 3, 4).map(_ + 10)).filter (_ % 2 == 0).toList #1 LazyList(2, 3, 4).map(_ + 10).filter (_ % 2 == 0).toList #2 cons(12, LazyList(3, 4).map(_ + 10)).filter (_ % 2 == 0).toList #3 12 :: LazyList(3, 4).map(_ + 10).filter (_ % 2 == 0).toList #4 12 :: cons(13, LazyList(4).map(_ + 10)).filter(_ % 2 == 0).toList 12 :: LazyList(4).map(_ + 10).filter(_ % 2 == 0).toList 12 :: cons(14, LazyList().map(_ + 10)).filter(_ % 2 == 0).toList 12 :: 14 :: LazyList().map(_ + 10).filter (_ % 2 == 0).toList #5 12 :: 14 :: List() #6
Trace how map, filter, and toList incrementally force a LazyList, producing only the elements required by the final result. section 5.3
