the lambda calculus David Walker CS 441 the (untyped) lambda calculus • a language of functions e ::= x | \x.e | e1 e2 v ::= \x.e • there are several different ways to evaluate lambda calculus expressions • so far, we’ve studied left-to-right, call-by-value: (b) (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ • amazingly, despite it’s minimalism, the lambda calculus is Turing complete and may serve as a foundation for all computation extending the lambda calculus • lambda calculus with booleans: e ::= x | true | false | test | \x.e | e1 e2 v ::= true | false | test | \x.e e1 --> e1’ (test1) test e1 e2 e3 --> test e1’ e2 e3 e2 --> e2’ (test2) test v1 e2 e3 --> test v1 e2’ e3 e3 --> e3’ (test3) test v1 v2 e3 --> test v1 v2 e3’ (test-false) (test-true) test true v2 v3 --> v2 test false v2 v3 --> v3 + all the other lambda calculus rules booleans: the translation • from +boolean into pure : target language source language values in the source language always get translated into values in the target language translate(true) = \t.\f. t translate(false) = \t.\f. f translate(test) = \x.\y.\z. x y z translate(x) = x translate(\x.e) = \x.(translate(e)) translate(e1 e2) = translate(e1) translate(e2) (b) boolean translation example: (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ translate(test true s1 s2) = (\x.\y.\z.x y z) (\x.\y.x) v1 v2 (where v1 = translate s1 and v2 = translate s2) (b) boolean translation example: (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ translate(test true s1 s2) = (\x.\y.\z.x y z) (\x.\y.x) v1 v2 (where v1 = translate s1 and v2 = translate s2) in the source language we have: test true s1 s2 --> s1 (b) boolean translation example: (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ translate(test true s1 s2) = (\x.\y.\z.x y z) (\x.\y.x) v1 v2 (where v1 = translate s1 and v2 = translate s2) in the source language we have: test true s1 s2 --> s1 so in the target we want: (\x.\y.\z.x y z) (\x.\y.x) v1 v2 --> v1 (b) boolean translation example: (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ translate(test true s1 s2) = (\x.\y.\z.x y z) (\x.\y.x) v1 v2 (where v1 = translate s1 and v2 = translate s2) in the source language we have: test true s1 s2 --> s1 so in the target we want: (\x.\y.\z.x y z) (\x.\y.x) v1 v2 --> v1 (b) boolean translation (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ Theorem (Translation Preserves Semantics): If s1 --> s2 (in the lambda calculus with booleans) then (translate(s1)) --> (translate(s2)) (in the pure lambda calc) booleans (b) (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ (((\x.\y.\z.x y z) (\x.\y.x)) v1) v2 --> _____________ (b) booleans (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ e1 ((\x.\y.\z.x y z) (\x.\y.x)) v1) --> ___________ (app1) (((\x.\y.\z.x y z) (\x.\y.x)) v1) v2 --> _____________ v2 e1 e1’ booleans (b) (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ (b) (\x.\y.\z.x y z) (\x.\y.x) --> ___________ (app1) (\x.\y.\z.x y z) (\x.\y.x)) v1 --> ___________ v1 (app1) (((\x.\y.\z.x y z) (\x.\y.x)) v1) v2 --> _____________ v2 booleans (b) (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ (b) \x.\y.\z.x y z (\x.\y.x) --> \y.\z.x y z [\x.\y.x / x] ((\x.\y.\z.x y z) (\x.\y.x)) v1) --> v1 (((\x.\y.\z.x y z) (\x.\y.x)) v1) v2 --> (app1) (app1) v2 booleans (b) (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ (b) \x.\y.\z.x y z (\x.\y.x) --> \y.\z.(\x.\y.x) y z ((\x.\y.\z.x y z) (\x.\y.x)) v1) --> (((\x.\y.\z.x y z) (\x.\y.x)) v1) v2 --> (app1) v1 (app1) v2 booleans (b) (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ (b) \x.\y.\z.x y z (\x.\y.x) --> \y.\z.(\x.\y.x) y z (app1) ((\x.\y.\z.x y z) (\x.\y.x)) v1) --> (\y.\z.(\x.\y.x) y z) v1 (((\x.\y.\z.x y z) (\x.\y.x)) v1) v2 --> v2 (app1) booleans (b) (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ (b) (\x.\y.\z.x y z) (\x.\y.x) --> \y.\z.(\x.\y.x) (app1) ((\x.\y.\z.x y z) (\x.\y.x)) v1) --> \y.\z.(\x.\y.x) v1 (((\x.\y.\z.x y z) (\x.\y.x)) v1) v2 --> \y.\z.(\x.\y.x) v1 v2 (app1) booleans translate(true) = \t.\f. t translate(false) = \t.\f. f translate(and) = \b.\c. b c (translate(false)) translate(x) = ... translate(and true true) = (\b.\c. b c (\t.\f.f)) (\t.\f.t) (\t.\f.t) booleans translate(true) = \t.\f. t translate(false) = \t.\f. f translate(and) = \b.\c. b c (translate(false)) translate(x) = ... translate(and true true) = (\b.\c. b c (\t.\f.f)) (\t.\f.t) (\t.\f.t) ===> wow is that ever tough to read ... booleans tru = \t.\f. t fls = \t.\f. f translate(and true true) = a tru tru = (\b.\c. b c fls) tru tru a = \b.\c. b c fls target language expression (ie: a and tru are just meta-variables I’m using to abbreviate and make more readable the translated term) booleans tru = \t.\f. t fls = \t.\f. f a = \b.\c. b c fls a tru tru = (\b.\c. b c fls) tru tru --> (\c.tru c fls) tru (b) (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ booleans tru = \t.\f. t fls = \t.\f. f a tru tru = (\b.\c. b c fls) tru tru --> (\c.tru c fls) tru --> tru tru fls a = \b.\c. b c fls (b) (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ booleans tru = \t.\f. t fls = \t.\f. f a tru tru = (\b.\c. b c fls) tru tru --> (\c.tru c fls) tru --> tru tru fls = (\t.\f. t) tru fls a = \b.\c. b c fls (b) (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ booleans tru = \t.\f. t fls = \t.\f. f a tru tru = (\b.\c. b c fls) tru tru --> (\c.tru c fls) tru --> tru tru fls = (\t.\f. t) tru fls -->(\f. tru) fls a = \b.\c. b c fls (b) (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ booleans tru = \t.\f. t fls = \t.\f. f a tru tru = (\b.\c. b c fls) tru tru --> (\c.tru c fls) tru --> tru tru fls = (\t.\f. t) tru fls -->(\f. tru) fls --> tru a = \b.\c. b c fls (b) (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ if statements (b) e ::= x | v | e1 e2 | if e1 then e2 else e3 v ::= \x.e | true | false e1 --> e1’ if e1 then e2 else e3 --> if e1’ then e2 else e3 if true then e2 else e3 --> e2 (if2) (if3) if false then e2 else e3 --> e3 (\x.e) v --> e [v/x] e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ (if1) An Example loop = (\x.x x) (\x.x x) if (\x.x) true then \x.x else loop --> if true then \x.x else loop --> \x.x 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) translate (\x.e) = \x.(translate e) translate (e1 e2) = (translate e1) (translate e2) booleans pure lambda terms: tru = \t.\f.t fls = \t.\f.f tst = \x.\y.\z. x y z • what is wrong with the following translation? translate true = tru translate false = fls translate (if e1 then e2 else e3) = tst (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 (b) (\x.e) v --> e [v/x] example e1 --> e1’ (app1) e1 e2 --> e1’ e2 translate (if (\x.x) true then \x.x else loop) = tst translate((\x.x) true) (translate(\x.x)) (translate(loop)) = tst ((\x.x) tru) (\x.x) (loop) = tst ((\x.x) tru) (\x.x) ((\x.x x) (\x.x x)) e2 --> e2’ (app2) v e2 --> v e2’ (b) (\x.e) v --> e [v/x] example e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ translate (if (\x.x) true then \x.x else loop) = tst translate((\x.x) true) (translate(\x.x)) (translate(loop)) = tst ((\x.x) tru) (\x.x) (loop) = tst ((\x.x) tru) (\x.x) ((\x.x x) (\x.x x)) tst ((\x.x) tru) (\x.x) ((\x.x x) (\x.x x)) --> tst tru (\x.x) ((\x.x x) (\x.x x)) (b) (\x.e) v --> e [v/x] example e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ translate (if (\x.x) true then \x.x else loop) = tst translate((\x.x) true) (translate(\x.x)) (translate(loop)) = tst ((\x.x) tru) (\x.x) (loop) = tst ((\x.x) tru) (\x.x) ((\x.x x) (\x.x x)) tst ((\x.x) tru) (\x.x) ((\x.x x) (\x.x x)) --> tst tru (\x.x) ((\x.x x) (\x.x x)) (((\x.\y.\z. x y z) tru) (\x.x)) ((\x.x x) (\x.x x)) --> (b) (\x.e) v --> e [v/x] example e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ translate (if (\x.x) true then \x.x else loop) = tst translate((\x.x) true) (translate(\x.x)) (translate(loop)) = tst ((\x.x) tru) (\x.x) (loop) = tst ((\x.x) tru) (\x.x) ((\x.x x) (\x.x x)) tst ((\x.x) tru) (\x.x) ((\x.x x) (\x.x x)) --> tst tru (\x.x) ((\x.x x) (\x.x x)) (((\x.\y.\z. x y z) tru) (\x.x)) ((\x.x x) (\x.x x)) --> ((\y.\z. tru y z) (\x.x)) ((\x.x x) (\x.x x)) --> (b) (\x.e) v --> e [v/x] example e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ translate (if (\x.x) true then \x.x else loop) = tst translate((\x.x) true) (translate(\x.x)) (translate(loop)) = tst ((\x.x) tru) (\x.x) (loop) = tst ((\x.x) tru) (\x.x) ((\x.x x) (\x.x x)) tst ((\x.x) tru) (\x.x) ((\x.x x) (\x.x x)) --> test tru (\x.x) ((\x.x x) (\x.x x)) (((\x.\y.\z. x y z) tru) (\x.x)) ((\x.x x) (\x.x x)) --> ((\y.\z. tru y z) (\x.x)) ((\x.x x) (\x.x x)) --> (( \z. tru (\x.x) z) ) ((\x.x x) (\x.x x)) --> (b) (\x.e) v --> e [v/x] example e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ translate (if (\x.x) true then \x.x else loop) = tst translate((\x.x) true) (translate(\x.x)) (translate(loop)) = tst ((\x.x) tru) (\x.x) (loop) = tst ((\x.x) tru) (\x.x) ((\x.x x) (\x.x x)) tst ((\x.x) tru) (\x.x) ((\x.x x) (\x.x x)) --> tst tru (\x.x) ((\x.x x) (\x.x x)) (((\x.\y.\z. x y z) tru) (\x.x)) ((\x.x x) (\x.x x)) --> ((\y.\z. tru y z) (\x.x)) ((\x.x x) (\x.x x)) --> (( \z. tru (\x.x) z) ) ((\x.x x) (\x.x x)) --> (( \z. tru (\x.x) z) ) ((\x.x x) (\x.x x)) --> (b) (\x.e) v --> e [v/x] example e1 --> e1’ (app1) e1 e2 --> e1’ e2 e2 --> e2’ (app2) v e2 --> v e2’ translate (if (\x.x) true then \x.x else loop) = tst translate((\x.x) true) (translate(\x.x)) (translate(loop)) = tst ((\x.x) tru) (\x.x) (loop) = tst ((\x.x) tru) (\x.x) ((\x.x x) (\x.x x)) tst ((\x.x) tru) (\x.x) ((\x.x x) (\x.x x)) --> tst tru (\x.x) ((\x.x x) (\x.x x)) (((\x.\y.\z. x y z) tru) (\x.x)) ((\x.x x) (\x.x x)) --> ((\y.\z. tru y z) (\x.x)) ((\x.x x) (\x.x x)) --> (( \z. tru (\x.x) z) ) ((\x.x x) (\x.x x)) --> (( \z. tru (\x.x) z) ) ((\x.x x) (\x.x x)) --> (( \z. tru (\x.x) z) ) ((\x.x x) (\x.x x)) --> ... booleans • we saw this translation didn’t work: translate (if e1 then e2 else e3) = tst (translate e1) (translate e2) (translate e3) • we need to delay execution of e2, e3 until the right time: translate (true) = \x.\y.(x (\x.x)) translate (false) = \x.\y.(y (\x.x)) translate (if e1 then e2 else e3) = (\x.\y.\z. x y z) (translate e1) (\w.translate e2) (\w.translate e3) ... other cases ... 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 pairs create = \x.\y.\b. b x y fst = \p. p tru sec = \p. p fls tru = \x.\y.x fls = \x.\y.y pairs create = \x.\y.\b. b x y fst = \p. p tru sec = \p. p fls fst (create tru fls) = fst ((\x.\y.\b. b x y) tru fls) tru = \x.\y.x fls = \x.\y.y pairs create = \x.\y.\b. b x y fst = \p. p tru sec = \p. p fls fst (create tru fls) = fst ((\x.\y.\b. b x y) tru fls) -->* fst (\b. b tru fls) tru = \x.\y.x fls = \x.\y.y pairs create = \x.\y.\b. b x y fst = \p. p tru sec = \p. p fls fst (create tru fls) = fst ((\x.\y.\b. b x y) tru fls) -->* fst (\b. b tru fls) = (\p.p tru) (\b. b tru fls) tru = \x.\y.x fls = \x.\y.y pairs create = \x.\y.\b. b x y fst = \p. p tru sec = \p. p fls fst (create tru fls) = fst ((\x.\y.\b. b x y) tru fls) -->* fst (\b. b tru fls) = (\p.p tru) (\b. b tru fls) --> (\b. b tru fls) tru tru = \x.\y.x fls = \x.\y.y pairs create = \x.\y.\b. b x y fst = \p. p tru sec = \p. p fls fst (create tru fls) = fst ((\x.\y.\b. b x y) tru fls) -->* fst (\b. b tru fls) = (\p.p tru) (\b. b tru fls) --> (\b. b tru fls) tru --> tru tru fls = (\x.\y.x) tru fls --> (\y.tru) fls --> tru tru = \x.\y.x fls = \x.\y.y 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