We now look at lambda calculus, the theoretical stuff that underlies functional programming. It was introduced by Alonzo Church to formalise two key concepts when dealing with functions in mathematics and logic namely: function definition and function application. In this lecture, we build enough stuff to get a lambda calculus evaluator.
1 |
|
We start with an example. Consider the squaring function, i.e. the function that maps to . In the notation of lambda calculus this is denoted as . This is called a lambda abstraction. Apply a function on an expression is written as . The key rule in expression evaluation is the -reduction: the expression reduces under -reduction to the expression with substituted in it. We now look at lambda calculus formally.
The goal of this lecture is to introduce basics of lambda calculus and on the way implement a small lambda calculus interpreter.
As with any other formal system we first define its abstract syntax. A lambda calculus expression is defined via the grammar
Here and expressions themselves. We now capture this abstract syntax as a Haskell data type
1 |
|
The notion of free and bound variables are fundamental to whole of mathematics. For example in the integral , the variable occurs free where as the variables occurs bound (to the corresponding ). Clearly the value of the expression does not depend on the bound variable; in fact we can write the same integral as .
In lambda calculus we say a variable occurs bound if it can be linked to a lambda abstraction. For example in the expression the variable is bound where as occurs free. A variable can occur free as well as bound in an expression --- consider in .
Formally we can define the free variables of a lambda expression as follows.
We turn this into haskell code
1 |
|
We often need to substitute variables with other expressions. Since it is so frequent we give a notation for this. By , we mean the expression obtained by replacing all free occurrence of in by . Let us code this up in haskell.
1 |
|
You are already familiar with this in mathematics. If we have an integral of the kind we can rewrite it as by a change of variable. The same is true for lambda calculus. We say call the ``reduction'' as the -reduction. However care should be taken when the new variable is chosen. Two pitfalls to avoid when performing -reduction of the expression to is
The variable should not be free in for otherwise by changing from to we have bound an otherwise free variable. For example if then becomes which is clearly wrong.
If has a free occurrence of in the scope of a bound occurrence of then we cannot perform change the bound variable to . For example consider . Then will become which is clearly wrong.
Clearly, one safe way to do -reduction on is to use a fresh variable , i.e. a variable that is neither free nor bound in . We write a helper function to compute all the variables of a lambda calculus expression.
1 |
|
We now give the code to perform a safe change of bound variables.
1 |
|
The way lambda calculus captures computation is through reduction. We already saw what is reduction. Under beta reduction, an expression reduces to , where denotes substitution of free occurrences of by . However, there is a chance that a free variable of could become bound suddenly. For example consider to be just and to be . Then reducing to will bind the free variable in .
We now give the code for reduction. It performs one step of beta reduction that too if and only if the expression is of the form .
1 |
|
We saw that for our evaluator we needed a source of fresh variables. Our function fresh is given a set of variables and its task is to compute a variable name that does not belong to the list. We use diagonalisation, a trick first used by Cantor to prove that Real numbers are of strictly higher cardinality than integers.
1 |
|
Read up about -normal forms. Write a function that converts a lambda calculus expression to its normal form if it exists. There are different evaluation strategies to get to -normal form. Code them all up.
The use of varOf
in -reduction is an overkill. See if it can be improved.
Read about -reduction and write code for it.