Title: the lambda calculus
1the lambda calculus
2the lambda calculus
- Originally, the lambda calculus was developed as
a logic by Alonzo Church in 1932 - Church says There may, indeed, be other
applications of the system than its use as a
logic. - Dave says Ill say
3Reading
4functions
- essentially every full-scale programming language
has some notion of function - the (pure) lambda calculus is a language composed
entirely of functions - we use the lambda calculus to study the essence
of computation - it is just as fundamental as Turing Machines
5syntax
- t,e x (a variable)
- \x.e (a function in ML fn x gt e)
- e e (function application)
6syntax
- the identity function
- \x.x
- 2 notational conventions
- applications associate to the left (like in ML)
- y z x is (y z) x
- the body of a lambda extends as far as possible
to the right - \x.x \z.x z x is \x.(x \z.(x z x))
7terminology
the scope of x is the term t
y is free in the term \x.x y
x is bound in the term \x.x y
8CBV operational semantics
- single-step, call-by-value OS t --gt t
- values are v \x.t
- primary rule (beta reduction)
- t v/x is the term in which all free occurrences
of x in t are replaced with v - this replacement operation is called substitution
- we will define it carefully later in the lecture
(\x.t) v --gt t v/x
9operational semantics
- search rules
- notice, evaluation is left to right
e1 --gt e1 e1 e2 --gt e1 e2
e2 --gt e2 v e2 --gt v e2
10Example
11Example
- (\x. x x) (\y. y)
- --gt x x \y. y / x
12Example
- (\x. x x) (\y. y)
- --gt x x \y. y / x
- (\y. y) (\y. y)
13Example
- (\x. x x) (\y. y)
- --gt x x \y. y / x
- (\y. y) (\y. y)
- --gt y \y. y / y
14Example
- (\x. x x) (\y. y)
- --gt x x \y. y / x
- (\y. y) (\y. y)
- --gt y \y. y / y
- \y. y
15Another example
16Another example
- (\x. x x) (\x. x x)
- --gt x x \x. x x/x
17Another example
- (\x. x x) (\x. x x)
- --gt x x \x. x x/x
- (\x. x x) (\x. x x)
- In other words, it is simple to write non
terminating computations in the lambda calculus - what else can we do?
18We can do everything
- The lambda calculus can be used as an assembly
language - We can show how to compile useful, high-level
operations and language features into the lambda
calculus - Result adding high-level operations is
convenient for programmers, but not a
computational necessity - Result make your compiler intermediate language
simpler
19Let Expressions
- It is useful to bind intermediate results of
computations to variables - let x e1 in e2
- Question can we implement this idea in the
lambda calculus?
source lambda calculus let
translate/compile
target lambda calculus
20Let Expressions
- It is useful to bind intermediate results of
computations to variables - let x e1 in e2
- Question can we implement this idea in the
lambda calculus? - translate (let x e1 in e2)
- (\x.e2) e1
21Let Expressions
- It is useful to bind intermediate results of
computations to variables - let x e1 in e2
- Question can we implement this idea in the
lambda calculus? - translate (let x e1 in e2)
- (\x. translate e2) (translate e1)
22Let Expressions
- It is useful to bind intermediate results of
computations to variables - let x e1 in e2
- Question can we implement this idea in the
lambda calculus? - translate (let x e1 in e2)
- (\x. translate e2) (translate e1)
- translate (x) x
- translate (\x.e) \x.translate e
- translate (e1 e2) (translate e1) (translate e2)
23booleans
- we can encode booleans
- we will represent true and false as functions
named tru and fls - how do we define these functions?
- think about how true and false can be used
- they can be used by a testing function
- test b then else returns then if b is true
and returns else if b is false - the only thing the implementation of test is
going to be able to do with b is to apply it - the functions tru and fls must distinguish
themselves when they are applied
24booleans
- the encoding
- tru \t.\f. t
- fls \t.\f. f
- test \x.\then.\else. x then else
25booleans
- tru \t.\f. t fls \t.\f. f
- test \x.\then.\else. x then else
- eg
- test tru (\x.t1) (\x.t2)
- --gt (\t.\f. t) (\x.t1) (\x.t2)
- --gt \x.t1
26booleans
- tru \t.\f. t fls \t.\f. f
- and \b.\c. b c fls
- and tru tru
- --gt tru tru fls
- --gt tru
27booleans
- tru \t.\f. t fls \t.\f. f
- and \b.\c. b c fls
- and fls tru
- --gt fls tru fls
- --gt fls
28booleans
- what is wrong with the following translation?
- translate true tru
- translate false fls
- translate (if e1 then e2 else e3)
- test (translate e1) (translate e2)
(translate e3) - ...
29booleans
- what is wrong with the following translation?
- translate true tru
- translate false fls
- translate (if e1 then e2 else e3)
- test (translate e1) (translate e2)
(translate e3) - ...
-- e2 and e3 will both be evaluated regardless of
whether e1 is true or false -- the target program
might not terminate in some cases when the
source program would
30pairs
- would like to encode the operations
- create e1 e2
- fst p
- sec p
- pairs will be functions
- when the function is used in the fst or sec
operation it should reveal its first or second
component respectively
31pairs
- create \fst.\sec.\bool. bool fst sec
- fst \p. p tru
- sec \p. p fls
- fst (create tru fls)
- --gt fst (\bool. bool tru fls)
- --gt (\bool. bool tru fls) tru
- --gt tru
32and we can go on...
- numbers
- arithmetic expressions (, -, ,...)
- lists, trees and datatypes
- exceptions, loops, ...
- ...
- the general trick
- values will be functions construct these
functions so that they return the appropriate
information when called by an operation
33Formal details
- In order to be precise about the operational
semantics of the lambda calculus, we need to
define substitution properly - remember the primary evaluation rule
(\x.t) v --gt t v/x
34substitution a first try
- the definition is given inductively
- x t/x t
- y t/x y (if y ? x)
- (\y.t) t/x \y.t t/x
- t1 t2 t/x (t1 t/x) (t2 t/x)
35substitution a first try
- This works well 50 of the time
- Fails miserably the rest of the time
- (\x. x) y/x \x. y
- the x in the body of (\x. x) refers to the
argument of the function - a substitution should not replace the x
- we got unlucky with our choice of variable
names
36substitution a first try
- This works well 50 of the time
- Fails miserably the rest of the time
- (\x. z) x/z \x. x
- the z in the body of (\x. z) does not refer to
the argument of the function - after substitution, it does refer to the argument
- we got unlucky with our choice of variable
names again!
37calculating free variables
- To define substitution properly, we must be able
to calculate the free variables precisely - FV(x) x
- FV(\x.t) FV(t) / x
- FV(t1 t2) FV(t1) U FV(t2)
38substitution
- x t/x t y t/x y
(if y ? x) - (\y.t) t/x \y.t (if y x)
- (\y.t) t/x \y.t t/x (if y ? x and y
? FV(t)) - t1 t2 t/x (t1 t/x) (t2 t/x)
39substitution
- almost! But the definition is not exhaustive
- what if y ? x and y ? FV(t) in the case for
functions - (\y.t) t/x \y.t (if y x)
- (\y.t) t/x \y.t t/x (if y ? x and y
? FV(t))
40alpha conversion
- the names of bound variables are unimportant (as
far as the meaning of the computation goes) - in ML, there is no difference between
- fn x gt x and fn y gt y
- we will treat \x. x and \y. y as if they are
(absolutely and totally) indistinguishable so we
can always use one in place of the other
41alpha conversion
- in general, we will adopt the convention that
terms that differ only in the names of bound
variables are interchangeable - ie \x.t \y. ty/x (where this is the latest
version of substitution) - changing the name of a bound variable is called
alpha conversion
42substitution, finally
- x t/x t y t/x y
(if y ? x) - (\y.t) t/x \y.t t/x (if y ? x and y
? FV(t)) - t1 t2 t/x (t1 t/x) (t2 t/x)
we use alpha-equivalent terms so this constraint
can always be satisfied. We pick y as we
like so this is true.
43operational semantics again
- Is this the only possible operational semantics?
(\x.t) v --gt t v/x
e1 --gt e1 e1 e2 --gt e1 e2
e2 --gt e2 v e2 --gt v e2
44alternatives
(\x.t) e --gt t e/x
(\x.t) v --gt t v/x
e1 --gt e1 e1 e2 --gt e1 e2
e1 --gt e1 e1 e2 --gt e1 e2
e2 --gt e2 v e2 --gt v e2
call-by-value
call-by-name
45alternatives
(\x.t) e --gt t e/x
(\x.t) v --gt t v/x
e1 --gt e1 e1 e2 --gt e1 e2
e1 --gt e1 e1 e2 --gt e1 e2
e2 --gt e2 e1 e2 --gt e1 e2
e2 --gt e2 v e2 --gt v e2
e --gt e \x.e --gt \x.e
call-by-value
full beta-reduction
46alternatives
(\x.t) e --gt t e/x
(\x.t) v --gt t v/x
e1 --gt e1 e1 ? v e1 e2 --gt e1 e2
e1 --gt e1 e1 e2 --gt e1 e2
e2 --gt e2 v e2 --gt v e2
e2 --gt e2 v e2 --gt v e2
e --gt e \x.e --gt \x.e
call-by-value
normal-order reduction
47alternatives
(\x.t) v --gt t v/x
(\x.t) v --gt t v/x
e1 --gt e1 e1 e2 --gt e1 e2
e1 --gt e1 e1 v --gt e1 v
e2 --gt e2 v e2 --gt v e2
e2 --gt e2 e1 e2 --gt e1 e2
call-by-value
right-to-left call-by-value
48summary
- the lambda calculus is a language of functions
- Turing complete
- easy to encode many high-level language features
- the operational semantics
- primary rule beta-reduction
- depends upon careful definition of substitution
- many evaluation strategies