Reading preferences
Optional display controls need JavaScript. All reading content and navigation work without it.
Source file content/lambda-calculus/introduction/introduction.tex
Editorial
This chapter consists of Jeremy's original concise notes on the lambda calculus. The sections need to be combined, and the material on lambda definability merged with the material in the separate, more detailed chapter on lambda definability.
Source file content/lambda-calculus/introduction/overview.tex
Overview
The lambda calculus was originally designed by Alonzo Church in the early 1930s as a basis for constructive logic, and not as a model of the computable functions. But it was soon shown to be equivalent to other definitions of computability, such as the Turing computable functions and the partial recursive functions. The fact that this initially came as a small surprise makes the characterization all the more interesting.
Lambda notation is a convenient way of referring to a function directly by a symbolic expression which defines it, instead of defining a name for it. Instead of saying “let source be the function defined by source,” one can say, “let source be the function source.” In other words, source is just a name for the function that adds three to its argument. In this expression, source is a dummy variable, or a placeholder: the same function can just as well be denoted by source. The notation works even with other parameters around. For example, suppose source is a function of two variables, and source is a natural number. Then source is the function which maps any source to source.
This way of defining a function from a symbolic expression is known as lambda abstraction. The flip side of lambda abstraction is application: assuming one has a function source (say, defined on the natural numbers), one can apply it to any value, like 2. In conventional notation, of course, we write source for the result.
What happens when you combine lambda abstraction with application? Then the resulting expression can be simplified, by “plugging” the applicand in for the abstracted variable. For example,
can be simplified to source.
Up to this point, we have done nothing but introduce new notations for conventional notions. The lambda calculus, however, represents a more radical departure from the set-theoretic viewpoint. In this framework:
Everything denotes a function.
Functions can be defined using lambda abstraction.
Anything can be applied to anything else.
For example, if source is a term in the lambda calculus, source is always assumed to be meaningful. This liberal framework is known as the untyped lambda calculus, where “untyped” means “no restriction on what can be applied to what.”
Digress
There is also a typed lambda calculus, which is an important variation on the untyped version. Although in many ways the typed lambda calculus is similar to the untyped one, it is much easier to reconcile with a classical set-theoretic framework, and has some very different properties.
Research on the lambda calculus has proved to be central in theoretical computer science, and in the design of programming languages. LISP, designed by John McCarthy in the 1950s, is an early example of a language that was influenced by these ideas.
Source file content/lambda-calculus/introduction/syntax.tex
The Syntax of the Lambda Calculus
One starts with a sequence of variables source, source, source, dots and some constant symbols source, source, source, dots. The set of terms is defined inductively, as follows:
Each variable is a term.
Each constant is a term.
If source is a term and source is a variable, then source is a term.
Terms of the form source are called applications and those of the form source abstractions.
The system without any constants at all is called the pure lambda calculus. We'll mainly be working in the pure source-calculus, so all lowercase letters will stand for variables. We use uppercase letters (source, source, etc.) to stand for terms of the source-calculus.
We will follow a few notational conventions:
Convention
When parentheses are left out, application takes place from left to right. For example, if source, source, source, and source are terms, then source abbreviates source.
Again, when parentheses are left out, lambda abstraction is to be given the widest scope possible. From example, source is read source.
A lambda can be used to abstract multiple variables. For example, source is short for source.
For example,
abbreviates
You should memorize these conventions. They will drive you crazy at first, but you will get used to them, and after a while they will drive you less crazy than having to deal with a morass of parentheses.
Two terms that differ only in the names of the bound variables are called source-equivalent; for example, source and source. It will be convenient to think of these as being the “same” term; in other words, when we say that source and source are the same, we also mean “up to renamings of the bound variables.” Variables that are in the scope of a source are called “bound”, while others are called “free.” There are no free variables in the previous example; but in
Source file content/lambda-calculus/introduction/reduction.tex
Reduction of Lambda Terms
What can one do with lambda terms? Simplify them. If source and source are any lambda terms and source is any variable, we can use source to denote the result of substituting source for source in source, after renaming any bound variables of source that would interfere with the free variables of source after the substitution. For example,
Digress
Alternative notations for substitution are source, source, and also source. Beware!
Intuitively, source and source have the same meaning; the act of replacing the first term by the second is called source-contraction. source is called a redex and source its contractum. Generally, if it is possible to change a term source to source by source-contraction of some subterm, we say that source source-reduces to source in one step, and write source. If from source we can obtain source with some number of one-step reductions (possibly none), then source source-reduces to source; in symbols, source. A term that cannot be source-reduced any further is called source-irreducible, or source-normal. We will say “reduces” instead of “source-reduces,” etc., when the context is clear.
Let us consider some examples.
We have
“Simplifying” a term can make it more complex:
It can also leave a term unchanged:
Also, some terms can be reduced in more than one way; for example,
by contracting the outermost application; and
by contracting the innermost one. Note, in this case, however, that both terms further reduce to the same term, source.
The final outcome in the last example is not a coincidence, but rather illustrates a deep and important property of the lambda calculus, known as the “Church--Rosser property.”
Source file content/lambda-calculus/introduction/church-rosser.tex
The Church--Rosser Property
The Church Rosser property
Let source, source, and source be terms, such that source and source. Then there is a term source such that source and source.
Uniqueness of normal form
Suppose source can be reduced to normal form. Then this normal form is unique.
Proof
If source and source, by the previous theorem there is a term source such that source and source both reduce to source. If source and source are both in normal form, this can only happen if source.
Finally, we will say that two terms source and source are source-equivalent, or just equivalent, if they reduce to a common term; in other words, if there is some source such that source and source. This is written source. Using the Church Rosser theorem, you can check that source is an equivalence relation, with the additional property that for every source and source, if source or source, then source. (In fact, one can show that source is the smallest equivalence relation having this property.)
Source file content/lambda-calculus/introduction/currying.tex
Currying
A source-abstract source represents a function of one argument, which is quite a limitation when we want to define function accepting multiple arguments. One way to do this would be by extending the source-calculus to allow the formation of pairs, triples, etc., in which case, say, a three-place function source would expect its argument to be a triple. However, it is more convenient to do this by Currying.
Let's consider an example. We'll pretend for a moment that we have a source operation in the source-calculus. The addition function is source-place, i.e., it takes two arguments. But a source-abstract only gives us functions of one argument: the syntax does not allow expressions like source. However, we can consider the one-place function source given by source, which adds source to its single argument source. Actually, this is not a single function, but a family of different functions “add source,” one for each number source. Now we can define another one-place function source as source. Applied to argument source, source returns the function source---so its values are other functions. Now if we apply source to source, and then the result to source we get: source. In this way, the one-place function source can do the same job as the two-place addition function. “Currying” simply refers to this trick for turning two-place functions into one place functions (whose values are one-place functions).
Here is an example properly in the syntax of the source-calculus. How do we represent the function source? If we want to define a function that accepts two arguments and returns the first, we can write source, which literally is a function that accepts an argument source and returns the function source. The function source accepts another argument source, but drops it, and always returns source. Let's see what happens when we apply source to two arguments:
In general, to write a function with parameters source, dots, source defined by some term source, we can write source. If we apply source arguments to it we get:
The last line literally means substituting source for source in the body of the function definition, which is exactly what we want when applying multiple arguments to a function.
Source file content/lambda-calculus/introduction/lambda-definability.tex
lambda definable Arithmetical Functions
How can the lambda calculus serve as a model of computation? At first, it is not even clear how to make sense of this statement. To talk about computability on the natural numbers, we need to find a suitable representation for such numbers. Here is one that works surprisingly well.
Definition of Church numerals
For each natural number source, define the Church numeral source to be the lambda term source, where there are source source's in all.
The terms source are “iterators”: on input source, source returns the function mapping source to source. Note that each numeral is normal. We can now say what it means for a lambda term to “compute” a function on the natural numbers.
Lambda definability of a partial function
Let source be an source-ary partial function from source to source. We say a source-term source lambda-defines source iff for every sequence of natural numbers source, dots, source,
if source is defined, and source has no normal form otherwise.
Lambda definability characterizes partial computability
A function source is a partial computable function if and only if it is lambda-defined by a lambda term.
Explain
This theorem is somewhat striking. As a model of computation, the lambda calculus is a rather simple calculus; the only operations are lambda abstraction and application! From these meager resources, however, it is possible to implement any computational procedure.
Source file content/lambda-calculus/introduction/lambda-computable.tex
lambda definable Functions are Computable
Lambda definable partial functions are computable
If a partial function source is lambda-defined by a lambda term, it is computable.
Proof
Suppose a function source is lambda-defined by a lambda term source. Let us describe an informal procedure to compute source. On input source, dots, source, write down the term source. Build a tree, first writing down all the one-step reductions of the original term; below that, write all the one-step reductions of those (i.e., the two-step reductions of the original term); and keep going. If you ever reach a numeral, return that as the answer; otherwise, the function is undefined.
An appeal to Church's thesis tells us that this function is computable. A better way to prove the theorem would be to give a recursive description of this search procedure. For example, one could define a sequence primitive recursive functions and relations, “source,” “source,” “source,” “source,” “source,” etc. The partial recursive procedure for computing source is then to search for a sequence of one-step reductions starting with source and ending with a numeral, and return the number corresponding to that numeral. The details are long and tedious but otherwise routine.
Source file content/lambda-calculus/introduction/computable-lambda.tex
Computable Functions are lambda definable
Computable partial functions are lambda definable
Every computable partial function is lambda-definable.
Proof
We need to show that every partial computable function source is lambda-defined by a lambda term source. By Kleene's normal form theorem, it suffices to show that every primitive recursive function is lambda-defined by a lambda term, and then that the functions lambda-definable are closed under suitable compositions and unbounded search. To show that every primitive recursive function is lambda-defined by a lambda term, it suffices to show that the initial functions are lambda-definable, and that the partial functions that are lambda-definable are closed under composition, primitive recursion, and unbounded search.
We will use a more conventional notation to make the rest of the proof more readable. For example, we will write source instead of source. While this is suggestive, you should remember that terms in the untyped lambda calculus do not have associated arities; so, for the same term source, it makes just as much sense to write source and source. But using this notation indicates that we are treating source as a function of three variables, and helps make the intentions behind the definitions clearer. In a similar way, we will say “define source by source” instead of “define source by source.”
Source file content/lambda-calculus/introduction/basic-pr-lambda.tex
The Basic Primitive Recursive Functions are lambda definable
Lambda definability of initial functions
The functions source, source, and source are lambda-definable.
Proof
The successor function source, is defined by source. You should think about why this works; for each numeral source, thought of as an iterator, and each function source, source is a function that, on input source, applies source source times starting with source, and then applies it once more.
There is nothing to say about projections: source. In other words, by our conventions, source is the lambda term source.
Source file content/lambda-calculus/introduction/composition.tex
The lambda definable Functions are Closed under Composition
Closure under composition
The lambda-definable functions are closed under composition.
Proof
Suppose source is defined by composition from source, source dots, source. Assuming source, source, dots, source are lambda-defined by source, source, dots, source, respectively, we need to find a term source that lambda-defines source. But we can simply define source by
In other words, the language of the lambda calculus is well suited to represent composition.
Source file content/lambda-calculus/introduction/primitive-recursion.tex
lambda definable Functions are Closed under Primitive Recursion
When it comes to primitive recursion, we finally need to do some work. We will have to proceed in stages. As before, on the assumption that we already have terms source and source that lambda-define functions source and source, respectively, we want a term source that lambda-defines the function source defined by
So, in general, given lambda terms source and source, it suffices to find a term source such that
for every natural number source; the fact that source and source lambda-define source and source means that whenever we plug in numerals source for source, source will normalize to the right answer.
But for this, it suffices to find a term source satisfying
In other words, with lambda trickery, we can avoid having to worry about the extra parameters source---they just get absorbed in the lambda notation.
Before we define the term source, we need a mechanism for handling ordered pairs. This is provided by the next lemma.
Representing ordered pairs by a lambda term
There is a lambda term source such that for each pair of lambda terms source and source, source and source.
Proof
First, define the lambda term source by
In other words, source is the term source. Looking at it differently, for every source, source is a constant function that returns source on any input.
Now define source by source. Then we have
as required.
The idea is that source represents the pair source, and if source is assumed to represent such a pair, source and source represent the left and right projections, source and source. We will use the latter notations.
Closure under primitive recursion
The lambda-definable functions are closed under primitive recursion.
Proof
We need to show that given any terms, source and source, we can find a term source such that
for every natural number source. The idea is roughly to compute sequences of pairs
using numerals as iterators. Notice that the first pair is just source. Given a pair source, the next pair, source is supposed to be equivalent to source. We will design a lambda term source that makes this one-step transition.
The details are as follows. Define source by
Now it is easy to verify that for any number source,
As suggested above, given source and source, define source by
In other words, on input source, source iterates source source times on source, and then returns the second component. To start with, we have
By induction on source, we can show that for each natural number one has the following:
For the second clause, we have
Here we have used the induction hypothesis on the second-to-last line. For the first clause, we have
Here we have used the second clause in the last line. So we have shown source and, for every source, source, which is exactly what we needed.
Source file content/lambda-calculus/introduction/fixed-point-combinator.tex
Fixed-Point Combinators
Suppose you have a lambda term source, and you want another term source with the property that source is source-equivalent to source. Define terms
and
using our notational conventions; in other words, source is the term source. Let source be the term source. Then we have
If one takes
then source and source reduce to a common term; so source. This is known as “Curry's combinator.” If instead one takes
then in fact source reduces to source, which is a stronger statement. This latter version of source is known as “Turing's combinator.”
Source file content/lambda-calculus/introduction/minimization.tex
The lambda definable Functions are Closed under Minimization
Closure under minimization
Suppose source is lambda-definable. Let source be defined by
Then source is lambda-definable.
Proof
The idea is roughly as follows. Given source, we will use the fixed-point lambda term source to define a function source which searches for a source starting at source; then source is just source. The function source can be expressed as the solution of a fixed-point equation:
Here are the details. Since source is primitive recursive, it is lambda-defined by some term source. Remember that we also have a lambda term source, such that source and source. Fixing source for the moment, to lambda-define source we want to find a term source (depending on source) satisfying
We can do this using the fixed-point term source. First, let source be the term
and then let source be the term source. Notice that the only free variable in source is source. Let us show that source satisfies the equation above.
By the definition of source, we have
In particular, for each natural number source, we have
as required. Notice that if you substitute a numeral source for source in the last line, the expression reduces to source if source reduces to source, and it reduces to source if source reduces to any other numeral.
To finish off the proof, let source be source. Then source lambda-defines source; in other words, for every source, source reduces to source, if source is defined, and has no normal form otherwise.
Source disclosures
- TR042-SAR-001: Source caveat. Merely occurring inside some lambda abstraction does not make a variable occurrence bound. The abstraction must bind that occurrence's variable name. The immediately following example correctly leaves y free inside lambda z. source
- TR042-SAR-002: Reader correction. In both displayed starting terms, the closing parenthesis after z is placed outside the lambda body, after its closing argument bracket. This restores the grouping used by the source's outermost and innermost contraction descriptions; no variable or reduction direction changes. source
- TR042-SAR-003: Source caveat. The final line changes the original body name from capital N to capital P without defining a new body. A one step reduction sign is also repeated across the first line break. Both are retained in the source record and explicitly identified in the spoken chain. source
- TR042-SAR-004: Source caveat. This definition lists k arguments but calls the function n ary. It also inserts a comma after capital F in the undefined-input expression, unlike the application in the displayed defined-input condition. The two notational inconsistencies are preserved and identified; the intended test concerns the same applied lambda term in both cases. source
- TR042-SAR-005: Source caveat. The displayed term is the Church numeral zero. The unary constant zero function requires a term that returns that numeral on every input; the numeral itself, when applied to one argument, instead returns the identity abstraction. The source identification is preserved rather than silently replaced. source
- TR042-SAR-006: Source caveat. This opening construction has several inconsistent names: it first asks for capital H where later it uses capital F; its successor equation passes z where the recursion variable is x; and its primed function names do not consistently match the following displays. The later parameter abstraction also passes an extra u to v. These source expressions are retained, not presented as a silently repaired construction. source
- TR042-SAR-007: Source caveat. The lemma assumes only lambda definability, but the proof here calls f primitive recursive. For a partial test function, an undefined test does not authorize moving to the next input; the least-zero search remains undefined. The source's otherwise clause and stronger assumption are preserved with this limitation stated. source