Lambda Calculus
The
Syntax
Let us first consider the untyped e
in the the untyped
e ::= v > variables like x, y and z | a > atoms like 1, 2, True, +, * | λv.e > function abstraction, such as def f(v): return e | e e' > function call a.k.a function application such as e(e')
Part of the motivation for this new language is for expressing higher-order functions. For example, if we wanted to define a function like:
def add(x): def g(y): return x + y return g
Doing so mathematically might be a little clumsy. Instead, with the
Just like in Python, the scope of a
We show the correspondence between terms in the
Python Expression | |
---|---|
lambda x: x + 1 | |
lambda x: lambda y: x(y) | |
(lambda x: 2 * x)(y) |
Function applications are left-associative, therefore e1(e2)(e3)
should be read as (e1(e2))(e3)
.
Semantics
To begin describing how
A variable
- bound if it is in the scope of a
in - free otherwise
Then, the functions
Now we want to be able to perform substitutions of variables with terms. For example, when we have an application of the form
def f(x): return x + 1f(2) # becomes 2 + 1 which is 3, because we substituted x with 2
However, this is not straightforward because we may introduce name clashes. For example, if we had
where is an atom since is not free if if and if and
We give some example applications of each rule:
(rename to before performing substitution)
The last rule of Definition 2 where variables are renamed to avoid name clashes introduces a form of equivalence known as
def f(x): return x + 1def f(y): return y + 1
In other words, if two terms differ only in the name of the bound variables, they are said to be
Finally, we get to the actual semantics of (lambda x: e1)(e2)
, evaluates to e1
where x
is substituted with e2
:
For example:
This is more-or-less how Python evaluates function calls:
>>> (lambda x: lambda y: x(y))(lambda x: x + 1)(2)3
Typed Variants
Python has types, which describes the class from which an object was instantiated:
>>> type(1)<class 'int'>>>> type(1.0)<class 'float'>
We will describe more on types in Chapter 2 (Types). But for now, know that we can also assign types to terms in the
For now, we shall restrict types to be the base types to only include int
, giving us a new language for the calculus:
Termse ::= v > variables like x, y and z | a > atoms like 1, 2, +, * | λv: t.e > function abstraction, such as def f(v: t): return e | e e' > function call a.k.a function application such as e(e')
Typest ::= int > base type constants, only including integers | t -> t' > type of functions; -> is right-associative
The introduction of types to the calculus now adds the notion of well-typedness to the language. Specifically, not all terms in the untyped
First we have typing environments
The validity of a typing judgement is shown by providing a typing derivation that is constructed using typing rules, which are inference rules:
Which basically states that if all the statements
Then, the simply-typed
- If a variable
has type in then in the context , has type
- If an atom
has type then we can also judge the type of accordingly
- Abstraction: If in a certain context we can assume that
has type to conclude has type , then the same context without this assumption shows that has type
- Application: If in a certain context
has type and has type , then has type
These rules can be used to perform type checking (the procedure of checking the well-typedness of a term) or type reconstruction (the procedure of finding the types of terms where their typing information is not present, as is the case in the untyped
For example, in our calculus we can show that
That means the following lambda expression in Python (assuming only int
exists as a base type) will have the same type:
>>> f = lambda x: lambda y: x(y) # (int -> int) -> int -> int>>> my_fn = lambda x: x + 1 # int -> int# f(my_fn): int -> int# f(my_fn)(3): int>>> f(my_fn)(3) # int4>>> type(f(my_fn)(3))class <'int'>
Footnotes
-
The actual untyped
calculus does not have atoms like numbers, booleans etc. However, for simplicity’s sake we shall include them in the language. The version we present is frequently termed the applied calculus, in contrast with usual presentations known as the pure calculus which omits atoms. ↩