Lazy evaluation defers an expression until its value is demanded. In strict code, a chain such as `map`, `filter`, and `map` traverses a list repeatedly, allocating intermediate lists that are immediately discarded. Laziness keeps the same compositional, higher-order style while allowing transformations to produce results only as a consumer requests them. section 5.0 section 5.6
Listing 5.1 Program trace for List
List(1,2,3,4).map(_ + 10).filter(_ % 2 == 0).map(_ * 3) List(11,12,13,14).filter(_ % 2 == 0).map(_ * 3) List(12,14).map(_ * 3) List(36,42)
The trace exposes the strict cost: each operation first constructs a complete list for the next operation. A lazy representation can instead interleave production, filtering, and consumption. section 5.0
A lazy list represents its head and tail as thunks—functions with no arguments that delay a computation. Forcing a thunk obtains its value. The `cons` smart constructor stores the head and tail in `lazy val`s, so a forced result is cached rather than recomputed. This permits a list to describe more elements than have yet been evaluated. section 5.2 section 5.6
Stopping when the answer is known
`exists(p)` tests the current head, then uses nonstrict `||` to avoid evaluating the tail when `p(h())` is true. A lazy `foldRight` generalizes this: its second argument is the unevaluated fold of the tail, and a combining function may discard it. `forAll`, `find`, `takeWhile`, and filtering can use the same ability to terminate or preserve only the demanded portion. section 5.3 section 5.6
This is more than an optimization. Laziness separates a computation’s description from the decision of how much to run. That separation makes one description reusable in contexts demanding different portions of its result, and it makes productive infinite sequences practical when consumers use operations such as `take`, `exists`, or lazy `foldRight`. section 5.3 section 5.5 section 5.6
Nonstrict parser combinators
Nonstrictness also matters when deferred work prevents divergence. A recursive parser `many` cannot use a strict second argument to `map2`, because constructing that argument recursively expands forever before parsing begins. Making `product`, `map2`, and left-biased `or` nonstrict in their second parser delays it until it is actually needed. section 9.2.1












