These web pages provide a practical introduction to lambda reduction, with a few pointers to more esoteric issues. I'm a linguist, and I have linguists in mind for my audience, so linguistic issues will be emphasized (e.g., a discussion of the interaction of lambda with other binding operators such as ∃ "exists" and ∀ "forall").
Browser issues: If your browser can handle JavaScript 1.2, and if you have JavaScript turned on, you will be able to evaluate examples by clicking on a button, and to make up your own examples to try; otherwise, the examples will just sit there. For instance, try clicking on the "Reduce" button:
Goal: Church's λ-calculus provides a convenient way of representing meanings, whether meanings of programs or of expressions in English or some other natural language. As a result, it is ubiquitous in computer science, logic, and formal approaches to the semantics of natural language. The λ-calculus consists of two things: a formal language and an associated notion of REDUCTION (roughly equivalent to "computation"). In the context of the lambda calculus, reduction is specifically called λ-reduction. What these pages will attempt to do is teach you how to perform λ-reduction accurately and confidently.
Other sources: I recommend Hankin's Lambda Calculi : A Guide for Computer Scientists (Oxford) for a readable survey, and Barendregt's The Lambda Calculus (Elsevier) for a more complete reference work. Barendregt and Barendsen's shorter introduction to the lambda calculus is also excellent. Selinger has an excellent set of lecture notes covering many logical and computational aspects of the lambda calculus. For a more linguistic perspective, chapter 2 of Carpenter's Type-Logical Semantics (MIT Press) presents a λ-calculus within a framework for describing natural language.
Acknowledgements: Saber Ben Salem made a number of helpful suggestions.
λ is a binding operator, just like backwards E ("∃") or upside down A ("∀"). Consequently, it always binds something (a variable), taking scope over some expression that (usually) contains occurrences of the bound variable. More practically, λ always occurs in the following configuration:
For instance:
Freedom is always relative to a particular expression. If the preceding expression is embedded within a larger one, the free variables can come to be bound:
The key notion of the λ-calculus is that it is possible to arrive at a logically equivalent expression by means of a process called λ-reduction. In the usual case, λ-reduction is actually a combination of three distinct reduction operations, each of which is discussed below. The key operation, the one that does the heavy lifting, is called β-reduction, and that is operation we will discuss first.
By the way, some people say "λ-conversion" instead of λ-reduction; others reserve "λ-conversion" to refer specifically to a single step in a series of reductions. This tutorial is trying not to be overly pedantic, so for present purposes I don't care.
Nothing happens until a λ-binding form occurs in construction with an argument, thus:
The main idea of β-reduction is to replace every free occurrence of the variable "var" in "body" with "argument". For instance, in the form below, both occurrences of "var" in the body are free.
Unfortunately, applying β-reduction indiscriminately can cause trouble when the body contains binding operators. Consider:
But consider what happens in this closely parallel but slightly different situation:
((λ x (λ y (x y))) y) | β-reduction: substitute "y" in for "x" in the body "(λ y (x y))" ==> |
(λ y (y y)) | |
Wrong result! |
The solution is to make use of alphabetic variants. Roughly, two expressions are "alphabetic variants" if they are identical except perhaps for the choice of variable symbols. For instance, the following expressions are alphabetic variants of one another:
Some examples of alphabetic variants:
1. | ((λ x x) x) | α-reduction on "(λ x x)", substituting "y1" for "x" ==> |
((λ y1 y1) x) | 2. | ((λ x x)(λ x (x x))) | α-reduction on "(λ x x)", substituting "y1" for "x" ==> |
((λ y1 y1)(λ x (x x))) | ||
3. | (λ x (λ x (x x))) | α-reduction on "(λ x (λ x (x x)))", substituting "y1" for "x" ==> |
(λ y1 (λ x (x x))) |
The third example may look surprising; the key fact is that α-reduction specifically targets only free occurrences of the variable in question (free relative to the λ body). Since the second λ binds the last two occurrences of "x", performing α-reduction on the larger form won't touch them.
Now, back to the original problem. The way to deal with "((λ x (λ y (x y))) y)", then, is to first take an alphabetic variant. Because alphabetic variants are guaranteed to be logically equivalent, we can substitute variants in place of the original sub expressions. If we do this cleverly, the "y" and the "z"'s don't interact in the pernicious manner shown above.
1. | ((λ x (λ y (x y))) y) | α-reduction on "(λ y (x y))", substituting "y1" for "y" ==> |
2. | ((λ x (λ y1 (x y1))) y) | β-reduction, substituting "y" for "x" ==> |
3. | (λ y1 (y y1)) |
Equivalent steps are taken automatically by the λ-reduction program:
It usually takes some practice to know when it is necessary to use an alphabetic variant. The safest strategy is to automatically apply α-reduction to every binding operator before each application of β-reduction. See if you can work out the right result for this form before clicking on the "Reduce" button; you will need three applications of β-reduction and at least one application of α-reduction:
(Warning:) I have modified the characterization of β-reduction and of α-reduction somewhat in the interests of simplicity. The simplified versions are perfectly sound, and provide the full expressive power of the λ-calculus. If you're interested in the traditional elaboration, consult either the Hankin book or Berendregt book mentioned above.
η-reduction says that an expression of the form "(λ x (P x))" is guaranteed to be equivalent to "P" alone, where "P" is any expression (in which x does not occur free). This equivalence is obvious enough, but α-reduction and β-reduction alone do not guarantee it. However, few practical applications of λ-reduction bother to implement η-reduction. In particular, the programs given on this page do not:
Some examples (try to guess the result before clicking):
Some more linguistically-related practice. Once again, try writing
down the anticipated result before clicking "Reduce":
Now for something a little more difficult. Find an expression that you can use to replace "X" so that the result is "(John sleeps)" (you will have to type it into the input window in place of "X" to try it):
Here's a harder problem: If the input is "((D man) sleep)", and the result is "(∃ x ((man x) & (sleep x)))", what is "D"? (Hint: the answer is an approximation of the meaning of the determiner "some", as in "Some man sleeps". The symbol "∃" is supposed to show up as a backwards E, and is usually read "there exists"; in any case, the program expects you to type it in to the window as the symbol "exists".)
It takes some practice to match up λ's with the correct argument. Does the following form evaluate to "(2 3)" or "(3 2)"?
In fact, when a form contains more than one λ that can be reduced, it does not matter which one is reduced first, the result will be the same. (This is known as the Church-Rosser property, or, informally, as the diamond property---see Hankin or Berendregt for lengthy discussion.) For instance, for the last example, we could either apply β-reduction to the innermost λ first, thus:
((λ x ((λ y (x y)) 2)) 3) | β-reduction on "((λ y (x y)) 2)", substituting "2" for "y" in the body "(x y)" ==> |
((λ x (x 2)) 3) | β-reduction, substituting "3" for "x" in the body "(x 2)" ==> |
(3 2) |
((λ x ((λ y (x y)) 2)) 3) | β-reduction on "((λ x ((λ y (x y)) 2)) 3)", substituting "3" for "x" in the body "((λ y (x y)) 2)" ==> |
((λ y (3 y)) 2) | β-reduction, substituting "2" for "y" in the body "(3 y)" ==> |
(3 2) |
That is, when the reduction converges at all---some expressions can't be simplified (e.g., "((λ x (x x))(λ x (x x)))", which reduces to itself, or more pathological examples, such as this (DON'T CLICK ON "REDUCE"!):
I have been writing predicates and their arguments inside parentheses, thus: "(pred arg)". Often in logic and linguistics, such an expression would be written "pred(arg)", for instance, "f(x)" (as in "f(x) = y"). I have chosen the first, more LISP-like notation because it significantly simplifies the design of the program for automating λ-reduction.
Often, instead of "(λ x (λ y (x y)))", people write "λ x y . x y". For some reason, these people hate to draw parentheses, and they hate to draw λ's. The dot shows where the list of bound variables stops and the (innermost) body begins. Because the scope of the λ operator(s) is not explicitly marked, sloppy use of this abbreviatory convention often leads to expressions that are ambiguous; this in turn often causes beginners tremendous frustration.