Lecture 17 (2018-03-20)
Lambda calculus: definition
We defined the lambda calculus, originated by Alonzo Church in the
1930s, worked on by some other famous folks (Stephen Kleene, Haskell
Curry Alan Turing). Here are the collected definitions.
### The lambda calculus

Let `V` be an infinite set of variable names.
We define the *terms* or *expressions* of the lambda calculus as follows:
```pre
e in LC ::= x | e1 e2 | lambda x. e
```
Note that application is left associative, so:
```pre
x y z = (x y) z
```
And that we write multiple variables after a lambda to indicate
nesting:
```pre
lambda x y z. e = lambda x. (lambda y. (lambda z. e))
```
### Free variables and substitution

We define the free variables of a term using the following function:
```pre
fv :: LC -> 2^V
fv(x) = {x}
fv(e1 e2) = fv(e1) U fv(e2)
fv(lambda x. e) = fv(e) \ {x}
```
We say *x is free in e* if `x is in fv(e)`. If a variable occurs in e
and it isn't free, we say it is *bound*. Every occurrence of a bound
variable appears under a lambda with that variable (prove this to
yourself!). For example:
```pre
fv(lambda x y z. q (x y)) = {q}
```
We say e is *closed* when `fv(e) = {}`. In general, we will only want to
think about closed terms---it's a strange idea to run a program with
free variables! If a term isn't closed, it's *open*.
Next, we define a *substitution* operation. We'll use a simple function
notation first, reading `subst(e1,x,e2)` as "substitute e2 for x in e1":
```pre
subst :: LC -> V -> LC -> LC
subst(x,x,e2) = e2
subst(y,x,e2) = y
subst(e11 e12,x,e2) = subst(e11,x,e2) subst(e12,x,e2)
subst(lambda x. e1,x,e2) = lambda x. e1
subst(lambda y. e1,x,e2) = lambda y. subst(e1,x,e2)
```
We typically write `e1[e2/x]` (read "e1 with e2 for x") to mean
`subst(e1,x,e2)`.
### Equational reasoning

Now we can give the two rules that define how the lambda calculus
behaves; both use substitution. First, there's *alpha equivalence*,
which says we can rename as long as we do so consistently:
```pre
lambda x. e = lambda y. e[y/x]
when y not in fv(e)
```
Second, there's *beta equivalence*, which says that we can substitute
actual arguments for formal arguments in a function:
```pre
(lambda x. e1) e2 = e1[e2/x]
```
Note that we get some other principles for free, because = is an
equivalence relation:
```pre
reflexivity: e = e
symmetry: e1 = e2 iff e2 = e1
transitivity: if e1 = e2 and e2 = e3 then e1 = e3
congruence (application): if e1 = e1' and e2 = e2' then e1 e2 = e1' e2'
congruence (lambda): if e = e' then lambda x. e = lambda x. e'
```
Using these two rules, we can reduce some lambda expressions. Try to
write out the whole derivation of these equalities yourself,
subscripting equality with alpha or beta to indicate when you use
alpha or beta equivalence, respectively. (Just like in algebra, we
don't need to make a big deal of it when we use properties like
reflexivity or congruence.)
```pre
(lambda x. x) (lambda y. y) = lambda y. y
(lambda x. z) (lambda y. y) = z
lambda x y. x = lambda a b. a
(lambda x y. x) (lambda z. z) (lambda c. d) = lambda z. z
```