Lazy evaluation means that expressions are not evaluated when they are bound to variables, but their evaluation is deferred until their results are needed by other computations. In consequence, arguments are not evaluated before they are passed to a function, but only when their values are actually used.
Non-strict semantics allows one to bypass undefined values (e.g. results of infinite loops) and in this way it also allows one to process formally infinite data.
When it comes to machine level and efficiency issues it is important whether or not equal objects share the same memory.A Haskell program cannot know whether
In many cases it is not necessary to know it, but in some cases the difference between shared and separated objects yields different orders of space or time complexity.Consider the infinite list
But with lazy evaluation (i.e. sharing) this becomes a list with a loop, a pointer back to the beginning. It only consumes constant space. In an imperative language (here Modula-3) the same would be achieved with the following code:
TYPE List = REF RECORD next: List; value: INTEGER; END;
VAR x := NEW(List, value:=1); BEGIN x.next := x; END;
Thus, lazy evaluation allows us to define cyclic graphs of pointers with warrantedly valid pointers. In contrast, C allows cyclic graphs of pointers, but pointers can be uninitialized, which is a nasty security hole. An eagerly evaluating functional language without hacks, would only allow for acyclic graphs of pointers.