15-150: Principles of Functional Programming

Lecture 18: Lazy Programming

In this lecture, we reviewed the evaluation semantics of SML, which is characterized by eager evaluation, meaning that all expressions are evaluated to values before stepping into the body of a function declaration. In other words, all variables range over values.

We then introduced the idea of lazy evaluation, which is where we simply substitute expressions directly into function bodies, without evaluating them first. This comes with some benefits, such as potential expression reuse and differing evaluation outcomes. One interesting thing is that in an eager language like SML, we can still simulate lazy evaluation using functions!

We introduced a new term of a thunk, which characterizes a function of type unit -> t, for some type t. A thunk is just a suspended computation, whose only role is to pause the evaluation of the resulting value until the function is supplied an argument, essentially only allowing the computation to proceed when explicitly requested.

Whereas all the data structures we have seen in this class so far have been finite, it turns out that lazy computations allowu s to define infinite data structures, data structures which can unboundedly give us more elements inside of it every time that an additional item is requested from it. Our premier example was that of a stream, which is like a list, but uses a mutually recursive datatype to not have to give up any elements contained inside until explicitly requested. We introduced the idea of maximal laziness to describe this, a data structure which does not expose any elements (even ones which may loop forever or raise exceptions) until absolutely needed.

We then went over several different examples of streams that we could define, as well as a small foray into an example of the Sieve of Eratosthenes as a case study for where we might find streams useful,

Slides