Lazy evaluation


In programming language theory, lazy evaluation, or call-by-need is an evaluation strategy which delays the evaluation of an expression until its value is needed and which also avoids repeated evaluations. The sharing can reduce the running time of certain functions by an exponential factor over other non-strict evaluation strategies, such as call-by-name, which repeatedly evaluate the same function, blindly, regardless whether the function can be memoized.
However, for lengthy operations, it would be more appropriate to perform before any time-sensitive operations, such as handling user inputs in a video game.
The benefits of lazy evaluation include:
Lazy evaluation is often combined with memoization, as described in Jon Bentley's Writing Efficient Programs. After a function's value is computed for that parameter or set of parameters, the result is stored in a lookup table that is indexed by the values of those parameters; the next time the function is called, the table is consulted to determine whether the result for that combination of parameter values is already available. If so, the stored result is simply returned. If not, the function is evaluated and another entry is added to the lookup table for reuse.
Lazy evaluation can lead to reduction in memory footprint, since values are created when needed. However, lazy evaluation is difficult to combine with imperative features such as exception handling and input/output, because the order of operations becomes indeterminate. Lazy evaluation can introduce memory leaks.
The opposite of lazy evaluation is eager evaluation, sometimes known as strict evaluation. Eager evaluation is the evaluation strategy employed in most programming languages.

History

Lazy evaluation was introduced for lambda calculus by Christopher Wadsworth and employed by the Plessey System 250 as a critical part of a Lambda-Calculus Meta-Machine, reducing the resolution overhead for access to objects in a capability-limited address space. For programming languages, it was independently introduced by Peter Henderson and James H. Morris and by Daniel P. Friedman and David S. Wise.

Applications

Delayed evaluation is used particularly in functional programming languages. When using delayed evaluation, an expression is not evaluated as soon as it gets bound to a variable, but when the evaluator is forced to produce the expression's value. That is, a statement such as x = expression; clearly calls for the expression to be evaluated and the result placed in x, but what actually is in x is irrelevant until there is a need for its value via a reference to x in some later expression whose evaluation could itself be deferred, though eventually the rapidly growing tree of dependencies would be pruned to produce some symbol rather than another for the outside world to see.
Delayed evaluation has the advantage of being able to create calculable infinite lists without infinite loops or size matters interfering in computation. For example, one could create a function that creates an infinite list of Fibonacci numbers. The calculation of the n-th Fibonacci number would be merely the extraction of that element from the infinite list, forcing the evaluation of only the first n members of the list.
For example, in the Haskell programming language, the list of all Fibonacci numbers can be written as:

fibs = 0 : 1 : zipWith fibs

In Haskell syntax, ":" prepends an element to a list, tail returns a list without its first element, and zipWith uses a specified function to combine corresponding elements of two lists to produce a third.
Provided the programmer is careful, only the values that are required to produce a particular result are evaluated. However, certain calculations may result in the program attempting to evaluate an infinite number of elements; for example, requesting the length of the list or trying to sum the elements of the list with a fold operation would result in the program either failing to terminate or running out of memory.

Control structures

In almost all common "eager" languages, if statements evaluate in a lazy fashion.
if a then b else c
evaluates, then if and only if evaluates to true does it evaluate, otherwise it evaluates. That is, either or will not be evaluated. Conversely, in an eager language the expected behavior is that
define f = 2 * x
set k = f
will still evaluate when computing the value of f even though is unused in function f. However, user-defined control structures depend on exact syntax, so for example
define g = if a then b else c
l = g
and would both be evaluated in an eager language. While in a lazy language,
l' = if h then i else j
or would be evaluated, but never both.
Lazy evaluation allows control structures to be defined normally, and not as primitives or compile-time techniques. If or have side effects or introduce run time errors, the subtle differences between and can be complex. It is usually possible to introduce user-defined lazy control structures in eager languages as functions, though they may depart from the language's syntax for eager evaluation: Often the involved code bodies and ) need to be wrapped in a function value, so that they are executed only when called.
Short-circuit evaluation of Boolean control structures is sometimes called lazy.

Working with infinite data structures

Many languages offer the notion of infinite data-structures. These allow definitions of data to be given in terms of infinite ranges, or unending recursion, but the actual values are only computed when needed. Take for example this trivial program in Haskell:

numberFromInfiniteList :: Int -> Int
numberFromInfiniteList n = infinity !! n - 1
where infinity =
main = print $ numberFromInfiniteList 4

In the function numberFromInfiniteList, the value of infinity is an infinite range, but until an actual value is needed, the list is not evaluated, and even then it is only evaluated as needed

List-of-successes pattern

Avoiding excessive effort

A compound expression might be in the form EasilyComputed or LotsOfWork so that if the easy part gives true a lot of work could be avoided. For instance, suppose a large number N is to be checked to determine if it is a prime number and a function IsPrime is available, but alas, it can require a lot of computation to evaluate. Perhaps N=2 or will help if there are to be many evaluations with arbitrary values for N.

Avoidance of error conditions

A compound expression might be in the form SafeToTry and Expression whereby if SafeToTry is false there should be no attempt at evaluating the Expression lest a run-time error be signalled, such as divide-by-zero or index-out-of-bounds, etc. For instance, the following pseudocode locates the last non-zero element of an array:
L:=Length;
While L>0 and A=0 do L:=L - 1;
Should all elements of the array be zero, the loop will work down to L = 0, and in this case the loop must be terminated without attempting to reference element zero of the array, which does not exist.

Other uses

In computer windowing systems, the painting of information to the screen is driven by expose events which drive the display code at the last possible moment. By doing this, windowing systems avoid computing unnecessary display content updates.
Another example of laziness in modern computer systems is copy-on-write page allocation or demand paging, where memory is allocated only when a value stored in that memory is changed.
Laziness can be useful for high performance scenarios. An example is the Unix mmap function, which provides demand driven loading of pages from disk, so that only those pages actually touched are loaded into memory, and unneeded memory is not allocated.
MATLAB implements copy on edit, where arrays which are copied have their actual memory storage replicated only when their content is changed, possibly leading to an out of memory error when updating an element afterwards instead of during the copy operation.

Implementation

Some programming languages delay evaluation of expressions by default, and some others provide functions or special syntax to delay evaluation. In Miranda and Haskell, evaluation of function arguments is delayed by default. In many other languages, evaluation can be delayed by explicitly suspending the computation using special syntax or, more generally, by wrapping the expression in a thunk. The object representing such an explicitly delayed evaluation is called a lazy future. Raku uses lazy evaluation of lists, so one can assign infinite lists to variables and use them as arguments to functions, but unlike Haskell and Miranda, Raku does not use lazy evaluation of arithmetic operators and functions by default.

Laziness and eagerness

Controlling eagerness in lazy languages

In lazy programming languages such as Haskell, although the default is to evaluate expressions only when they are demanded, it is possible in some cases to make code more eager—or conversely, to make it more lazy again after it has been made more eager. This can be done by explicitly coding something which forces evaluation or avoiding such code. Strict evaluation usually implies eagerness, but they are technically different concepts.
However, there is an optimisation implemented in some compilers called strictness analysis, which, in some cases, allows the compiler to infer that a value will always be used. In such cases, this may render the programmer's choice of whether to force that particular value or not, irrelevant, because strictness analysis will force strict evaluation.
In Haskell, marking constructor fields strict means that their values will always be demanded immediately. The seq function can also be used to demand a value immediately and then pass it on, which is useful if a constructor field should generally be lazy. However, neither of these techniques implements recursive strictness—for that, a function called deepSeq was invented.
Also, pattern matching in Haskell 98 is strict by default, so the ~ qualifier has to be used to make it lazy.

Simulating laziness in eager languages

Python

In Python 2.x the range function computes a list of integers. The entire list is stored in memory when the first assignment statement is evaluated, so this is an example of eager or immediate evaluation:

>>> r = range
>>> print r
>>> print r

In Python 3.x the range function returns a special range object which computes elements of the list on demand. Elements of the range object are only generated when they are needed, so this is an example of lazy or deferred evaluation:

>>> r = range
>>> print
range
>>> print

In Python 2.x is possible to use a function called xrange which returns an object that generates the numbers in the range on demand. The advantage of xrange is that generated object will always take the same amount of memory.

>>> r = xrange
>>> print
xrange
>>> lst =
>>> print

From version 2.2 forward, Python manifests lazy evaluation by implementing iterators unlike tuple or list sequences. For instance :

>>> numbers = range
>>> iterator = iter
>>> print numbers
>>> print iterator

>>> print iterator.next

.NET Framework

In the.NET Framework it is possible to do lazy evaluation using the class System.Lazy. The class can be easily exploited in F# using the lazy keyword, while the force method will force the evaluation. There are also specialized collections like Microsoft.FSharp.Collections.Seq that provide built-in support for lazy evaluation.

let fibonacci = Seq.unfold
fibonacci |> Seq.nth 1000

In C# and VB.NET, the class System.Lazy is directly used.

public int Sum

Or with a more practical example:

// recursive calculation of the n'th fibonacci number
public int Fib
public void Main

Another way is to use the yield keyword:

// eager evaluation
public IEnumerable Fibonacci
// lazy evaluation
public IEnumerable LazyFibonacci