Download presentation
Presentation is loading. Please wait.
Published byRonnie Tarrant Modified over 9 years ago
1
the lambda calculus David Walker CS 441
2
the 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: “I’ll say”
3
Reading Pierce, Chapter 5
4
functions 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
5
syntax t,e ::= x(a variable) | \x.e(a function; in ML: fn x => e) | e e(function application)
6
syntax 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))”
7
terminology \x.t \x.x y the scope of x is the term t x is bound in the term \x.x y y is free in the term \x.x y
8
CBV operational semantics single-step, call-by-value OS: t --> 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 --> t [v/x]
9
operational semantics search rules: notice, evaluation is left to right e1 --> e1’ e1 e2 --> e1’ e2 e2 --> e2’ v e2 --> v e2’
10
Example (\x. x x) (\y. y)
11
Example (\x. x x) (\y. y) --> x x [\y. y / x]
12
Example (\x. x x) (\y. y) --> x x [\y. y / x] == (\y. y) (\y. y)
13
Example (\x. x x) (\y. y) --> x x [\y. y / x] == (\y. y) (\y. y) --> y [\y. y / y]
14
Example (\x. x x) (\y. y) --> x x [\y. y / x] == (\y. y) (\y. y) --> y [\y. y / y] == \y. y
15
Another example (\x. x x)
16
Another example (\x. x x) --> x x [\x. x x/x]
17
Another example (\x. x x) --> 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?
18
We 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
19
Let 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 target = lambda calculus translate/compile
20
Let 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
21
Let 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)
22
Let 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)
23
booleans 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
24
booleans the encoding: tru = \t.\f. t fls = \t.\f. f test = \x.\then.\else. x then else
25
booleans tru = \t.\f. t fls = \t.\f. f test = \x.\then.\else. x then else eg: test tru (\x.t1) (\x.t2) -->* (\t.\f. t) (\x.t1) (\x.t2) -->* \x.t1
26
booleans tru = \t.\f. t fls = \t.\f. f and = \b.\c. b c fls and tru tru -->* tru tru fls -->* tru
27
booleans tru = \t.\f. t fls = \t.\f. f and = \b.\c. b c fls and fls tru -->* fls tru fls -->* fls
28
booleans 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)...
29
booleans 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
30
pairs 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
31
pairs create = \fst.\sec.\bool. bool fst sec fst = \p. p tru sec = \p. p fls fst (create tru fls) -->* fst (\bool. bool tru fls) -->* (\bool. bool tru fls) tru -->* tru
32
and 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
33
Formal 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 --> t [v/x]
34
substitution: 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])
35
substitution: 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
36
substitution: 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!
37
calculating 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)
38
substitution 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])
39
substitution 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))
40
alpha 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 => x and fn y => 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
41
alpha 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. t[y/x] (where this is the latest version of substitution) –changing the name of a bound variable is called alpha conversion
42
substitution, 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.
43
operational semantics again Is this the only possible operational semantics? e1 --> e1’ e1 e2 --> e1’ e2 e2 --> e2’ v e2 --> v e2’ (\x.t) v --> t [v/x]
44
alternatives e1 --> e1’ e1 e2 --> e1’ e2 e2 --> e2’ v e2 --> v e2’ (\x.t) v --> t [v/x] e1 --> e1’ e1 e2 --> e1’ e2 (\x.t) e --> t [e/x] call-by-value call-by-name
45
alternatives e1 --> e1’ e1 e2 --> e1’ e2 e2 --> e2’ v e2 --> v e2’ (\x.t) v --> t [v/x] e1 --> e1’ e1 e2 --> e1’ e2 (\x.t) e --> t [e/x] call-by-value full beta-reduction e2 --> e2’ e1 e2 --> e1 e2’ e --> e’ \x.e --> \x.e’
46
alternatives e1 --> e1’ e1 e2 --> e1’ e2 e2 --> e2’ v e2 --> v e2’ (\x.t) v --> t [v/x] e1 --> e1’ e1 ≠ v e1 e2 --> e1’ e2 (\x.t) e --> t [e/x] call-by-value normal-order reduction e2 --> e2’ v e2 --> v e2’ e --> e’ \x.e --> \x.e’
47
alternatives e1 --> e1’ e1 e2 --> e1’ e2 e2 --> e2’ v e2 --> v e2’ (\x.t) v --> t [v/x] call-by-value right-to-left call-by-value e1 --> e1’ e1 v --> e1’ v e2 --> e2’ e1 e2 --> e1 e2’ (\x.t) v --> t [v/x]
48
summary 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
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.