Lazy Evaluation

Fixme work in progress

In the most basic way possible, laziness is the ability to evaluate an expression only when it’s actually needed. Taken further, lazyness is also evalating an expression only to the extent required.

Lazyness in definition

Lazyness in evaluation

Lazyness in partial evaluation

Clojure is not entirely lazy, only the majority of sequence operations like map, reduce, filter or repeatedly are lazy evaluated.

The most common use of laziness are infinite lists or streams. For example, we could define a list of all prime numbers. In case you didn’t know, that’s a lot of prime numbers (infinitely many).

If we would define such list in a language like C++ or Python then the language would try to calculate all prime numbers immediately, which would run literally forever.

If we define such list in Haskell or Clojure, then nothing is calculated just yet. As a matter of fact we could happily print out the first 1000 prime numbers from that list without running into a problem. Again, because lazy evaluation only calculates what is really needed, and nothing more.

Lazyness in number calculation - Ratio type

Dividing an integer value by another results in a Ratio type if the result would otherwise result in a decimal number. Clojure only partially evaluates this expression.

  1. (/ 22 7)

We can also just express a value as a ratio. This works because of the prefix notation of Clojure

  1. 22/7

The lazyness can be overridden by specifying a precision, eg coersing the result into a specific type

  1. (/ 22 7.0)
  2. (double (/ 22 7))
  3. (float (/ 22 7))

Making something lazy

The range function returns a sequence of numbers limited by any arguents given when calling the range function.

Calling the range function without arguments will force an infinate sequence of numbers to be generated, quickly resulting in an out of memory error in the heap.

Instead, we can either pass arguments to the range function that limit the sequence size or wrap the range function in another function

  1. (take 7 (range))

The take function defines how much of a sequence that range should generate. So we can call range without arguments and it will generate only those numbers in the sequence as specified by take.

References