The Lambda Calculus

Chapter: The Lambda Calculus

Alonzo Church lived from 1903 to 1995. In the 1930s he introduced the lambda calculus as a way for mathematics to reason about functions. Later, in the 1960s, computer scientists rediscovered the concept and found it to be a marvelous tool for understanding the nature of computation.

There are three kinds of expression in the lambda calculus:

Q. 1
Did you notice that Scheme expressions form a superset of the lambda calculus?

Accordingly, we shall, for the rest of the lab, abandon the standard lambda calculus notation with the . and use standard Scheme notation.

I could, at this stage, ask you to write a syntax checker and parser for the language "lambda calculus". Instead, I'll give you my code:

(define var? (lambda (x) (symbol? x)))

(define lambda? 
  (lambda (x) 
    (and (eq? (car x) 'lambda)       ; begins with lambda
         (var? (var-of x))           ; lists one parameter
         (null? (cdr (cadr x)))      ; and only one
         (exp? (body-of x))          ; body is a lambda calculus expression
         (null? (cdddr x))           ; only one body

(define var-of caadr)
(define body-of caddr)

(define app?
  (lambda (x)
    (and (exp? (operator-of x))         ; first is a lambda calculus expression
         (exp? (operand-of x))          ; so is second
         (null? (cddr x))               ; there is no third or subsequent

(define operator-of car)
(define operand-of cadr)

(define exp?
  (lambda (x)
     (var? x)
     (lambda? x)
     (app? x))))

There are two kinds of variables: Some are free and some are bound In an abstraction lambda (x) body lambda is said to bind occurrences of x within its body. For example, in (lambda (x) ((y x) x)) the lambda binds both occurrences of x. In this example the y is a free variable.

The lambda operator does not bind every occurrence of its variable because "shadowing" can occur. A variable is bound by its nearest enclosing lambda. In (lambda (x) ((y x) (lambda (x) (x y)))) the x in (y x) is bound by the outermost lambda, whereas the x in (x y) is bound by the inner lambda. In this example, both occurrences of y are free.

Here is a recursive definition of what it means to be a free variable in a lambda calculus expression:

Exercise 1

Write a procedure occurs-free so that (occurs-free var exp) returns true when the variable var occurs free in the expression exp.
> (occurs-free 'y '(lambda (x) (y x)))
> (occurs-free 'x '(lambda (x) (y x)))
> (occurs-free 'x '(x (lambda (y) x)))
> (occurs-free 'y '(x (lambda (y) x)))

Similarly we can define what we mean by a variable occurring bound in a lambda calculus expression.

Exercise 2

Write a predicate occurs-bound so that (occurs-bound var exp) tells you if var occurs bound in exp.
> (occurs-bound 'x 'x)
> (occurs-bound 'x '(x (lambda (x) y)))
> (occurs-bound 'x '(x (lambda (x) x)))
> (occurs-free 'x '(x (lambda (x) x)))
Save all your code, including any code of mine that you borrowed, in a file called

Note how it's possible for the same variable to both occur free and occur bound in the same lambda calculus expression.

Now we know what the expressions of the lambda calculus are, you are probably eager to know what you can do with them. There are three reduction rules that can be applied to lambda calculus expressions:

  1. alpha reduction, the consistent renaming of a bound variable. For example (lambda (x) (x y)) can alpha-reduce to (lambda (z) (z y)). But the renaming must not result in the capture of a variable. It is not permissible to alpha-reduce (lambda (x) (x y)) by renaming x to y, as in (lambda (y) (y y)) as this would result in changing the meaning of the expression.
  2. beta reduction, the substitution of an actual argument for a parameter. For example ((lambda (x) (x y)) z) beta-reduces to (z y). In general, beta reduction is defined by ((lambda (var) body) arg) reducing to body(with arg substitute for var throughout).
  3. eta conversion recognizes that foo and (lambda (x) (foo x)) are identical in meaning so long as x does not occur free in foo. In general eta-reduction allows substitution of f for (lambda (x) (f x)).

I hope you recognize that beta-reduction is essentially what your Scheme interpreter does! It is interesting to observe that the lambda calculus with these three reduction rules gives a powerful and complete model of what function definition and application can do in mathematics. beta-reduction suffices for most programming computations. We need to be careful of eta-conversion when we start to look at lambda calculus in a programming context. It is not always true that f can safely be substituted for (lambda (x) (f x)).

Q. 2
Why not?

You may complain that so far lambda calculus is pretty useless because there is no concept of actual data! Oh don't be so fussy! There are many ways to add the natural numbers to the lambda calculus. One way is via Church numerals which would have:

(lambda (f) (lambda (x) x)) represent 0
(lambda (f) (lambda (x) (f x))) represent 1
(lambda (f) (lambda (x) (f (f x)))) represent 2
and so on. In general n is represented by a function that composes its argument with itself n times.

Q. 3
This is all very theoretical. Will you please stop?