It seems lazy evaluation of expressions can cause a programmer to lose control over the order in which their code is executed. I am having trouble understanding why this would be acceptable or desired by a programmer.
How can this paradigm be used to build predictable software that works as intended, when we have no guarantee when and where an expression will be evaluated?
Best Answer
A lot of the answers are going into things like infinite lists and performance gains from unevaluated parts of the computation, but this is missing the larger motivation for laziness: modularity.
The classic argument is laid out in the much-cited paper "Why Functional Programming Matters" (PDF link) by John Hughes. The key example in that paper (Section 5) is playing Tic-Tac-Toe using the alpha-beta search algorithm. The key point is (p. 9):
The Tic-Tac-Toe program can be written as a function that generates the whole game tree starting at a given position, and a separate function that consumes it. At runtime this does not intrinsically generate the whole game tree, only those subparts that the consumer actually needs. We can change the order and combination in which alternatives are produced by changing the consumer; no need to change the generator at all.
In an eager language, you can't write it this way because you would probably spend too much time and memory generating the tree. So you end up either: