Lambda Calculus: Introduction
Lambda calculus, λ-calculus, is a formal system in mathematical logic for expressing computation, and in that aspect it is equivalent to a Turing machine.
Lambda Calculus is a prototype programming languages invented by Alonzo Church in the 1930's, a functional language based on function abstraction and function application, using parameter binding and substitution.
Lambda Calculus is a higher-order language: it provides a systematic syntax for functions whose input and output values are other functions.
Lambda Calculus offers alternative approach to the representation of natural numbers. Majority of the set theories define, e.g. number 3, as the property that all sets containing 3 elements have in common; other set theories (e.g. stratified) define number 3 as the set that contains all sets with 3 elements. Set theories are built around the concept of a set as the most primitive notion, but, in Lambda Calculus a function plays that role.
In fact, only functions exist in Lambda Calculus. Everything else (boolean constants, numbers, data structures, etc.) has to be defined from scratch. This process begins by defining a function abstraction (i.e. a function definition) then, somewhat arbitrarily, assigning a meaning to it.
Lambda Calculus defines natural numbers in terms of functions (of course, since there's nothing else), that is, number 3 is represented as applying a function 3 times to its argument. Akin to other definitions of natural numbers, number zero is stated as an axiom and the successor function, that produces the subsequent natural numbers, is defined. So a number n is an n-fold of successor function to the zero argument.
Lambda calculus consists of constructing lambda terms and performing reduction operations on them.
Informal introduction
Lamda calculus has only 3 kinds of expressions: variables, abstraction (i.e. function definition) and function application.
Variables:
infinite set of vars (with sub/superscript if needed) e.g.
Abstraction:
is (anonymous) function definition, e.g. defines a function that takes a parameter, , and returns the evaluated body (the expression after the dot), in this case just (id function).
Application: applying a function to an expression, e.g. applies the id function to .
, associate to the left: is
associate to the right:
Formal introduction
Assume given an infinite set of variables, denoted by
The set of lambda terms is given by the following Backus-Naur Form
( and are lambda terms, is a variable)
Traditional introduction:
Assume given an infinite set of variables
Let be an alphabet consisting of the elements of and the special symbols:
λ
,.
,(
,)
Let be the set of strings (finite sequences) over the alphabet
The set of lambda terms is the smallest subset such that:
Whenever then
Whenever then
Whenever and then
Syntax
There are 3 kinds of λ-expressions: 1. Variables, , e.g. 2. Application, , which means i.e. application of expression to expression . 3. Abstractions, , represent the anonymous function which evaluates to (returns) the value when given formal parameter .
Association
Application, , associate to the left:
Abstraction, , associate to the right:
Convention
Juxtaposed abstraction, , can be shorthanded as
Parenthesis are used to disambiguate expressions or to enforce evaluation order: application is interpreted as , to enforce right-associativity, write
Abstraction
A lambda function is an abstraction over a lambda expression: where is a formal parameter and is a (sub)expression.
Examples of abstractions:
Greek letter lambda introduces a name used for abstraction.
taht name is function's bound variable (here ) and it represents a formal parameter similar to function declarations in PL.
The dot separates the name (formal parameter) from the function's body.
function's body is an expression in which abstraction with that name (actual parameter) takes place.
expression (in function's body) may be any lambda expression, including another function abstraction.
Similarity with programming languages
Lambda abstraction (assuming the function +
was defined, as infix):
</details>
Variables
Variables that are named in an abstraction are considered bound; e.g. λx.xyx
is a lambda expression in which the variable x
occurs bound, while the variable y
occurs free.
If a bound parameter does not appear in the body of a function, it just gets thrown away.
An occurrence of a variable
x
within a subexpressione
inλx.e
is a bound variable.An occurrence of an unbound variable is a free variable.
The occurrence of
x
in the abstraction's head,λx.
, is the binding occurrence, which introduces the variablex
The occurrence of bound
x
in the abstraction's body is called applied occurrences.If some occurrence of
x
is free in the subexpression then that is a free occurrence of variablex
.A variable
x
is bound by the syntactically innermost enclosingλ
, if one exists, just as in any block-structured programming language.Closed expression contains no free variables.
Open expression contains free variables.
Combinators are lambda abstractions without free variables.
The same variable may occur both bound and free in an expression. For example, the first applied occurrence of in is bound, but the second and third applied occurrences are free.
We can index all occurances of x to better see that the first occurance of i.e. is bound by , while the two other occurances, and , are free.
Alpha-conversion
The substitution of for the free occurrences of in , written , is defined:
and for a variable , if ,
For applications, we substitute into the two parts:
If then
If is a variable distinct from , and then
if does not appear free in ,
if does appear free in ,
where is a variable which does not appear in or .
Note that we have an infinite collection of variables,
so that we can always find such a "z".
In general, it is easy to see that if is not free in
then is
Application
A function application specialises an abstraction by providing a value for the name (formal parameter). The function expression contains the abstraction to be specialised with the argument expression. In a function application, also known as a bound pair, the function expression is said to be applied to the argument expression.
When the function is applied to argument , :
the value of the argument () is assigned to the formal parameter
the head of the function is dropped ()
the actual parameters in the function's body (bound params with the same name as the formal param) are replaced with the value
the expression evaluates to
The process of evaluation of a λ-expression is called simplification or β-reduction (beta-reduction).
In general, to evaluate application of a lambda abstraction, i.e. we replace the actual parameters in the function's body with the formal parameter - this substitution is denoted by .
Lazy and strict evaluation
There are two approaches to evaluating a function applications:
strict evaluation: by value i.e. applicative order
lazy evaluation: by reference i.e. normal order
The former approach is called applicative order and it is similar to "call by value" in PL in that the value of the argument is evaluated before being assigned as the value of the formal parameter.
The second approach is called normal order and it is similar to "call by reference" in PL in that the value of the argument is assigned to the formal parameter unevaluated.
All occurences of the function's bound variable in the function's body expression are replaced by either the value of the argument expression or the unevaluated argument expression.
In most cases the evaluation order amounts to the same result, but sometimes the order does matter, to the point of evaluation decidibility.
For example
here the argument expression, , is either evaluated first and only then applied to the abstraction, , or it is applied immediately unevaluated:
by value (evaluate the arg before applyng it):
by reference (apply the arg unevaluated):
</details>
Currying
Lambda functions take one parameter at the time. In order to supply more then one parameter, there can be one function per argument: the first function accepts the first parameter and returns the second function that accepts the second parameter (with the first parameter fixed), and so on.
The function is the same as , which is the same as .
When it is applied, , the argument is bound by the outer abstraction (parameter ), while the argument is bound by the inner (parameter ):
Examples
Examplary expressions
Example: Evaluating a lambda expression
(assuming the function +
was defined, as infix)
Example: Evaluation i.e. beta reduction
Example: evaluation fork
Example: constant function (unused bound parameter)
Example expressions:
</details>
Last updated
Was this helpful?