Lazy evaluation, also called non-strict evaluation, is the strategy of not computing the value of an expression until that value is actually demanded by some other part of the program. Where a strict language evaluates a function’s arguments before calling it, a lazy language passes them unevaluated and forces them only on demand. The Haskell site describes this directly: in Haskell “functions don’t evaluate their arguments,” and the language uses lazy evaluation by default.
In his paper “Why Functional Programming Matters,” John Hughes argues that lazy evaluation is one of two features that make functional programming powerful, alongside higher-order functions. He frames laziness as a kind of glue: it lets a program that generates a large or even infinite amount of data be cleanly separated from a program that consumes only as much of it as it needs, so the two can be written and reasoned about independently.
This separation is what makes infinite data structures practical. A lazy program can describe, for example, the unbounded list of all natural numbers, and only the portion that is actually inspected is ever computed. Combined with caching of already-forced values, this can also avoid repeating work that turns out not to be needed.
The trade-off is that the order and timing of computation become harder to predict. Because work is deferred until demanded, it can be difficult to reason about exactly when something runs or how much memory is held while a deferred computation waits, which is a recurring practical concern in lazy languages.