Lazy Evaluation
Simple example: Infinite sequence
Lazy evaluation allows the creation of things like infinite data structures. One example is the definition of an endless sequence:
This small feature ones
creates an instance of list
that starts with the head value 1
followed by a tail that
is ones
as well. The tail is performed lazily through a function
call to ones
only when needed.
We can now take an arbitrary number of elements from this sequence, e.g.,
using a call to take
as shown in the following example that creates
sequences of 5 and 50 elements:
What happens here?
On a call to ones
, a Cons
-cell is created that
contains a head value 1
and a function to create the tail when
needed. This tail function calls ones
when the tail of this list
is requested.
Dangers
Infinite data structures like this may easily result in infinite loops or infinite recursion. It is, e.g., not possible to count the elements of the infinite list above:
or to convert that list into a string:
Lazy evaluation for performance
In addition to making infinite structure possible, another important aspect of lazy evaluation is that it avoids run-time overhead for the evaluation of values if these values are not needed. An example would be a logging mechanism as follows:
This code runs very slowly just because the logging messages are created.
A more efficient alternative uses lazy evaluation as follows:
In the lazy version, the msg
parameter for log
is
no longer of type String
but now has type () ->
String
, i.e., a function producing a string. This function is called
implicitly when needed.
Additionally, the message parameter passed to log
now is a
lambda of the form ()->"..
that creates the original string when
called.