Computer Science Theory

Lecture 19: November 28, 2012

Lambda Calculus I

- Lambda calculus was introduced in the 1930s by Alonzo Church as a mathematical system for defining computable functions.
- Lambda calculus is equivalent in definitional power to that of Turing machines.
- Lambda calculus serves as the model for functional programming languages.
- Lisp was developed by John McCarthy in 1956 around lambda calculus.
- ML, a general purpose functional programming language, was developed by Robin Milner in the late 1970s.
- Haskell, considered by many as one of the purest functional programming languages, was developed by Simon Peyton Jones, Paul Houdak, Phil Wadler and others in the late 1980s and early 90s.

- The central concept in lambda calculus is an expression which can denote either a function definition (called a function abstraction) or a function application.

```
expr → abstraction | application | (expr) | var | constant
abstraction → λ var . expr
application → expr expr
```

- A function abstraction, often called a lambda abstraction, is an expression defining a function.
- It consists of a lambda followed by a variable, a period, and then an expression: λ var . expr
- In the function λ var . expr, var is the formal parameter and expr the body.
- We say λ var . expr
*binds*var in expr. - Example
- λx.y is a function abstraction.
- The variable x after the λ is the formal parameter of the function.
- The expression y after the period is the body of the function.

- A function application, often called a lambda application, consists of an expression followed by an expression.
- Example 1: if e is a function and f an expression, then ef is a function application. The expression f is the argument of the function e.
- Example 2: in (λx.y)z, we are applying the function λx.y to the argument z.

- The grammar for lambda expressions in section 2 is ambiguous.
- Several conventions overcome the ambiguities:
- Function application is left associative.
- Example 1: efg = (ef)g
- Application binds tighter than period.
- Example 2: (λx. λy. xy) λz.z = (λx. (λy. xy)) λz.z
- The body of a lambda extends as far to the right as possible.
- Example 3: λx.x λy.xyx = λx.(x λy.xyx))

- In lambda calculus all variables are local to function definitions.
- In the function λx.x the variable x in the body of the definition
(the second x) is
*bound*because its first occurrence in the definition is λx. - In the expression (λx.xy), the variable x in the
body of the function is bound and the variable y is
*free*. - In the expression (λx.x)(λy.yx):
- The variable x in the body of the leftmost expression is bound to the first lambda.
- The variable y in the body of the second expression is bound to the second lambda.
- The variable x in the body of the second expression is free.
- Note that x in second expression is independent of the x in the first expression.
- In the expression (λx.xy)(λy.y):
- The variable y in the body of the leftmost expression is free.
- The variable y in the body of the second expression is bound to the second lambda.
- Given an expression e, the following recursive rules define FV(e), the set of free variables in e:
- If e is a variable x, then FV(e) = {x}.
- If e is of the form λx.y, then FV(e) = FV(y) - {x}.
- If e is of the form xy, then FV(e) = FV(x) ∪ FV(y).
- An expression with no free variables is said to be closed.

- The name of the parameter variable in function definition is arbitrary.
We can use any variable to name a parameter, so that the function
λx.x is equivalent to λy.y and λz.z.
This kind of renaming is called
*alpha reduction*. - Note that we cannot rename free variables in expressions.
- Also note that we cannot change the name of a bound variable in an expression to conflict with the name of a free variable in that expression.

- A function application fg is evaluated by substituting the argument g for the formal parameter in the body of the function definition f.
- The notation [y/x]e is used to indicate that y is to be substituted for all free occurrences of x in the expression e.
- Example: (λx.x)y → [y/x]x = y
- This substitution in a function application is called a
*beta reduction*and we use a right arrow to indicate a beta reduction. - If expr1 → expr2, we say expr1 reduces to expr2 in one step.
- In general, (λx.e)g → [g/x]e means that applying the function (λx.e) to the argument expression g reduces to the function body [g/x]e after substituting the argument expression g for the function's formal parameter x in the function body e.
- A lambda-calculus expression (aka a "program") is "run" by computing a final result by the application of zero or more beta reductions. We use →* to denote the reflexive and transitive closure of →.
- Examples
- (λx.x)y → y (illustrating that λx.x is the identity function).
- (λx.xx)(λy.y) → (λy.y)(λy.y) → (λy.y); thus, we can write (λx.xx)(λy.y) →* (λy.y);.

- In standard lambda calculus, the only name for a function is an expression denoting the function.
- When we want to apply a function to an argument, we write down the whole function definition and then proceed to evaluate it on the argument.
- As an example, let us apply the identify function to itself:
- (λx.x)(λy.y) → [λy.y/x]x = λy.y which by alpha reduction is the same as λx.x
- Thus, as expected, the identify function applied to itself yields the identity function.
- When performing substitutions, we should be careful to avoid mixing up free occurrences of a variable with bound ones.
- When we apply the function λx.e to an expression f, we substitute all occurrences of x in e with f. If there is a free variable in f named x, we rename the bound variable x in the function definition to avoid any conflicts before doing the substitution.
- The rules for substitution are as follows. We assume x and y are distinct variables.
- For variables
- [e/x]x = e
- [e/x]y = y, assuming x ≠ y
- For function applications
- [e/x](f g) = ([e/x]f) ([e/x]g)
- For function abstractions
- [e/x](λx.f) = λx.f
- [e/x](λy.f) = λy.[e/x]f, provided y is not a free variable in e.
- Examples:
- The expression (λx.(λy.xy))y) contains a bound y in the middle
and a free y at the right. We therefore should rename the bound variable y to a new variable,
say z, to evaluate the expression with no name conflicts:

(λx.(λy.xy))y) = (λx.(λz.xz))y) → [y/x](λz.xz) = (λz.yz) - The body of the leftmost expression in (λx.(λy.(x(λx.xy))))y is (λy.(x(λx.xy))). In this body only the first x is free. Before substituting, we need to rename the bound variable y to z, say, to avoid confusing it with its free occurrence. Therefore we get the evaluation: (λx.(λy.(x(λx.xy))))y = (λx.(λz.(x(λx.xz))))y → [y/x](λz.(x(λx.xz))) = (λz.(y(λx.xz)))

- An expression containing no more possible beta reductions is called a normal form.
- Any expression not containing a function application in it somewhere is a normal form.
- Examples of normal form expressions:
- x where x is a variable
- xe where x is a variable and e is a normal form expression
- λx.e where x is a variable and e is a normal form expression
- The expression (λz.z z) (λz.z z) does not have a normal form because it always evaluates to itself. We can think of this expression as a representation for an infinite loop.
- A remarkable property of lambda calculus is that every expression has a unique normal form if one exists.
- Lambda calculus is also Church-Rosser, meaning that reductions can be applied in any order. More formally, if w →* x and w →* y, then there always exists an expression z such that x →* z and y →* z.

- Evaluate
- (λa.λb.a)c((λd.e)e)
- (λx.a)((λx.xx)((λy.yy))
- (λx.fx)a
- (λy.c((λz.fz)b)

- http://www.inf.fu-berlin.de/lehre/WS01/ALPI/lambda.pdf
- http://www.soe.ucsc.edu/classes/cmps112/Spring03/readings/lambdacalculus/project3.html
- Stephen Edwards notes on Lambda Calculus

aho@cs.columbia.edu