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:

**variables**, such as x, y, etc.- lambda abstractions, such as lambda x . exp, where exp is an expression
- applications (exp1 exp2) where exp1 and exp2 are expressions

**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) (or (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:

- x occurs free in
`x` - x occurs free in
`lambda (y) E`if x is not y and x occurs free in E - x occurs free in
`(E F)`if x occurs free in E or x occurs free in F.

> (occurs-free 'y '(lambda (x) (y x))) #t > (occurs-free 'x '(lambda (x) (y x))) #f > (occurs-free 'x '(x (lambda (y) x))) #t > (occurs-free 'y '(x (lambda (y) x))) #f >

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

- No variable occurs bound in
`x` - x occurs bound in
`(lambda (y) E)`if x occurs bound in E, or if x and y are the same and y occurs free in E - x occurs bound in (E F) if x occurs bound in E or x occurs bound in F

> (occurs-bound 'x 'x) #f > (occurs-bound 'x '(x (lambda (x) y))) #f > (occurs-bound 'x '(x (lambda (x) x))) #t > (occurs-free 'x '(x (lambda (x) x))) #t >Save all your code, including any code of mine that you borrowed, in a file called ex1.ss.

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:

**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.**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).**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 2and 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?

rhyspj@gwu.edu