the lambda calculus

48
the lambda calculus David Walker CS 441

description

the lambda calculus. David Walker CS 441. 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”. Reading. - PowerPoint PPT Presentation

Transcript of the lambda calculus

Page 1: the lambda calculus

the lambda calculus

David WalkerCS 441

Page 2: the lambda calculus

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”

Page 3: the lambda calculus

Reading

• Pierce, Chapter 5

Page 4: the lambda calculus

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

Page 5: the lambda calculus

syntax

t,e ::= x (a variable) | \x.e (a function; in ML: fn x =>

e) | e e (function application)

Page 6: the lambda calculus

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))”

Page 7: the lambda calculus

terminology

• \x.t

• \x.x y

the scope of x is the term t

x is boundin the term \x.x y

y is free in the term \x.x y

Page 8: the lambda calculus

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]

Page 9: the lambda calculus

operational semantics

• search rules:

• notice, evaluation is left to right

e1 --> e1’e1 e2 --> e1’ e2

e2 --> e2’v e2 --> v e2’

Page 10: the lambda calculus

Example

(\x. x x) (\y. y)

Page 11: the lambda calculus

Example

(\x. x x) (\y. y)--> x x [\y. y / x]

Page 12: the lambda calculus

Example

(\x. x x) (\y. y)--> x x [\y. y / x]== (\y. y) (\y. y)

Page 13: the lambda calculus

Example

(\x. x x) (\y. y)--> x x [\y. y / x]== (\y. y) (\y. y)--> y [\y. y / y]

Page 14: the lambda calculus

Example

(\x. x x) (\y. y)--> x x [\y. y / x]== (\y. y) (\y. y)--> y [\y. y / y]== \y. y

Page 15: the lambda calculus

Another example

(\x. x x) (\x. x x)

Page 16: the lambda calculus

Another example

(\x. x x) (\x. x x)--> x x [\x. x x/x]

Page 17: the lambda calculus

Another example

(\x. x x) (\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?

Page 18: the lambda calculus

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

Page 19: the lambda calculus

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

Page 20: the lambda calculus

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

Page 21: the lambda calculus

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)

Page 22: the lambda calculus

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) = xtranslate (\x.e) = \x.translate etranslate (e1 e2) = (translate e1) (translate e2)

Page 23: the lambda calculus

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

Page 24: the lambda calculus

booleans

• the encoding:

tru = \t.\f. t

fls = \t.\f. f

test = \x.\then.\else. x then else

Page 25: the lambda calculus

booleans

tru = \t.\f. t fls = \t.\f. ftest = \x.\then.\else. x then else

eg:

test tru (\x.t1) (\x.t2) -->* (\t.\f. t) (\x.t1) (\x.t2) -->* \x.t1

Page 26: the lambda calculus

booleans

tru = \t.\f. t fls = \t.\f. fand = \b.\c. b c fls

and tru tru -->* tru tru fls -->* tru

Page 27: the lambda calculus

booleans

tru = \t.\f. t fls = \t.\f. fand = \b.\c. b c fls

and fls tru -->* fls tru fls -->* fls

Page 28: the lambda calculus

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)...

Page 29: the lambda calculus

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 regardlessof whether e1 is true or false-- the target program might not terminate in some cases when the source program would

Page 30: the lambda calculus

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

Page 31: the lambda calculus

pairs

create = \fst.\sec.\bool. bool fst secfst = \p. p trusec = \p. p fls

fst (create tru fls)-->* fst (\bool. bool tru fls)-->* (\bool. bool tru fls) tru-->* tru

Page 32: the lambda calculus

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

Page 33: the lambda calculus

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]

Page 34: the lambda calculus

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])

Page 35: the lambda calculus

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

Page 36: the lambda calculus

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!

Page 37: the lambda calculus

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)

Page 38: the lambda calculus

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])

Page 39: the lambda calculus

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))

Page 40: the lambda calculus

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

Page 41: the lambda calculus

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

Page 42: the lambda calculus

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 likeso this is true.

Page 43: the lambda calculus

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]

Page 44: the lambda calculus

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

Page 45: the lambda calculus

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’

Page 46: the lambda calculus

alternatives

e1 --> e1’e1 e2 --> e1’ e2

e2 --> e2’v e2 --> v e2’

(\x.t) v --> t [v/x]

e1 --> e1’ e1 ≠ ve1 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’

Page 47: the lambda calculus

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]

Page 48: the lambda calculus

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