CSE 230: Winter 2008 Principles of Programming Languages Lecture 13: The λ-Calculus Calculus Ranjit R jit Jh Jhala l UC San Diego Review • The lambda calculus is a calculus of functions: e := x | λx. λx e | e1 e2 • SSeverall evaluation l strategies exist b based d on β-reduction: (λx.e) e’ →β [e’/x] e The Order of Evaluation Normal Forms λ-term λ term can have many β β-redexes redexes (λx. (λx E) E E’ (λy. (λx. x) y) E • A term without redexes is in normal form Reduce the inner or the outer application ? (λ y. (λ x. x) y) E inner outer (λ y. [y/x] x) E = (λ y. y) E [E/y] (λ x. x) y =(λ x. x) E E • A reduction sequence stops at a normal form – If e in normal form and e →*β e’ then e ≡ e’ • (λx.λy. x) is in normal form • (λx.λy. x) (λz. z) is not in normal form The Diamond Property The Diamond Property • Relation R has diamond p property p y if: R whenever e R e1 and e R e2 , there exists e’ such that e1 R e’ and e2 R e’ e1 e R e2 R R e’ • →β does not have the diamond property. – For example, example consider (λx. (λx x x x)(λy x)(λy. (λx (λx. x) y) • →β* has the diamond property Languages defined by nondeterministic rules: – – – – Logic programming languages Expert p systems y Constraint satisfaction systems Make Useful to know if systems have diamond property! • If so, a unique result is guaranteed – The proof is quite technical The Diamond Property Equality Languages defined by nondeterministic rules: =β : symmetric, reflexive, transitive closure of →β =β is (→β ∪ ←β)* – – – – Logic programming languages Expert p systems y Constraint satisfaction systems Make Useful to know if systems have diamond property! • If so, a unique result is guaranteed So e1 =β e2 if e1 converts to e2 via a seq q of forward and backward →β : • e1 • • e2 The Church Church-Rosser Rosser Theorem If e1 =β e2 then exists e e’ s.t. e1 →β* e e’ and e2 →β* e e’ • • e2 • e1 • • e’ • Proof (informal): apply the diamond property as many times as necessary. necessary Corollaries If e1 =β e2 and e1, e2 are normal forms then e1 ≡ e2 Proof: • From CR we have ∃e ∃e’. e1 →*β e e’ and e2 →*β e e’ • As e1, e2 are normal forms they are ≡ e’ If e →*β e1 and e →*β e2 and e1 , e2 are normal forms then e1 ≡ e2 Proof ? Significance: Each term reduces to one normal form Evaluation Strategies Normal-Order Normal Order Reduction Q: Which β-redex should be picked ? Good news, Church-Rosser Theorem: independent of strategy, there is at most one normal form outermost redex: a redex not contained inside another redex (λe λf. (λe. λf e) ((λa.λb. ((λa λb a) x y) ((λc.λd. ((λc λd c) u v) Bad news, some strategies may fail to find a normal form: – (λx. y) ((λy.y y) (λy.y y)) → (λx. y) ((λy.y y) (λy.y y)) → … – (λx. y) ((λy.y y) (λy.y y)) → y We consider three strategies: – normal – call-by-name – call-by-value Outermost: Normal order: leftmost outermost redex first Theorem: If e has a normal form e e’ then normal order reduction will reduce e to e’. Weak vs Strong Reduction Call-by-Name Call by Name Reduction In most PL, functions considered “fully evaluated” • Weak Reduction: • Don Don’tt reduce under λ • Don’t evaluate the argument to a function call – No reduction done under lambdas – i.e. inside a function body • Strong Reduction: – Reduction is done under lambdas – Partial evaluation of function, other optimizations Normal order reduces under lambda • λx.((λy.y (( y y y) ((λy.y y y y)) → λx.((λy.y (( y y y) ((λy.y y y y)) → … • Not always desired … Call by Name Call-by-Name Example (λ (λx. (λy. (λ x)) y)) ((λ ((λu. u)) (λ (λv. v)) )) →β (λy. y) ((λu. u) (λv. v)) →β (λu. u) (λv. v) →β λv. λv v – Directly substitute; evaluate when reducing body • Demand Demand-driven driven – an expression is not evaluated unless needed in body • Normalizing – it converges whenever normal order converges – but does not always evaluate to a normal form Call-by-Value Call by Value Reduction • Don Don’tt reduce under lambda • Do evaluate argument to function call • Most languages are call-by-value • Not normalizing – (λx. y) ((λy.y y) (λy.y y)) – diverges, but normal order (or CBN) converges Call by Value Call-by-Value CBV vs vs. CBN • Call-by-value: Evaluate arg • Example: (λ (λx. (λy. (λ x)) y)) ((λ ((λu. u)) (λ (λv. v)) )) →β (λy. (λx. x) y) (λv. v) →β (λy. y) (λv. v) →β λv. λv v – Easy to implement – May diverge • Call-by-name: – More difficult to implement p • must pass unevaluated expressions • Args multiply-evaluated inside function body – Simpler theory than call call-by-value by value • Terminates more often (always if normal form exists) • e.g. if arg is non-terminating, but not used … • Various V i other th reduction d ti strategies… t t i Programming with the λ λ-calculus calculus How does the λ λ-calculus calculus relate to “real” programming languages ? • Bools B l ? • If-then-else ? • Integers ? • Recursion ? • Functions: well, those we have … Functional Programming λ-calculus λ calculus = prototypical functional PL: – – – – no side effects, several evaluation strategies, strategies lots of functions, nothing but functions Q: How can we program with functions ? • Are they a sufficient “abstraction” ? Functional Programming Variables in Functional Languages • Lisp, Scheme, ML, Haskell … • We can introduce new variables: • Pure: No “locations”, “update”, (side)“effects” • Functions as args to/results from other functions: – Higher Higher-order order programming • Some “impure” functional languages – permit side-effects (e.g., Lisp, Scheme, ML, OCaml) – references (pointers), arrays, exceptions let x = e1 in e2 – x is bound by let – i.e., i x is i statically t ti ll scoped d in i e2 – essentially like (λx. e2) e1 • Variables are never updated – just names for expressions – e.g., x is a name for the value denoted by e1 in e2 • Equivalent to meaning of “let” in mathematics Why ? Referential Transparency • Enables reasoning equationally, by substitution: let x = e1 in e2 ≡ [e1/x]e2 • Imp. langs: “side-effects” side effects in e1 invalidate equation – evaluation of e_1 can alter semantics of e_2 • (f e_1) 1) and d (f e_2) 2) can produce d diff different results l – even if e_1 and e2 evaluate to the same thing! • FP: function’s behavior depends only on arguments – Doesn’t matter how function was called/used before! – No N state, t t lik like a mathematical th ti l ffunction ti – Localizes, simplifies understanding, reasoning about FP Expressiveness of λ λ-Calculus Calculus • λ calculus can express: – data types (ints, bools, pairs, lists, trees,…) – branching – Recursion • Enough to encode Turing machines – Corollary: e =β e’ is undecidable • But how to encode using g onlyy λ ? – Idea: encode the “behavior” of values Encoding Booleans in λ λ-calculus calculus Boolean Operations Q: What can we do with a boolean? A: Make a binary choice Q: So, how can you view this as a “function” ? A: Bool = fun that takes two choices, returns one • true =def λx. λy. y x • false =def λx. λy. y • if E1 then E2 else E3 =def E1 E2 E3 Boolean operations: not Example: “if if true then u else vv” is Function takes b: returns function takes x,y: returns “opposite” of b’s return not =def λb.(λx.λy. b y x) Boolean operations: or Function takes b1, b2: returns function takes x,y: returns (if b1 then x else (if b2 then x else y)) or =def λb1.λb2.(λx.λy. b1 x (b2 x y)) (λx. λy. x) u v →β (λy. u) v →β u Encoding Pairs (and so, Records) Encoding Natural Numbers Q: What can we do with a pair ? A: We can select one of its elements Q: What can we do with a natural number ? A: Iterate a number of times over some function Pair: function takes a bool, returns the left or the right element mkpair e1 e2 =def λb. b e1 e2 Note: “pair” encoded as λ-abstraction, “waiting” for bool fst p =def p true snd p =def p false Ex: fst (mkpair x y) → (mkpair x y) true → true x y → x Nat: function that takes fun f, f starting value s: returns: f applied to s a number of times 0 =def λf. λf λs. λ s 1 =def λf. λs. f s 2 =def λf. λf λs. λs f (f s) M Called Church numerals, numerals unary representation Note: (n f s) : apply f to s “n” times, i.e. fn(s) Operating on Natural Numbers • Testing equality with 0 iszero n =def n (λb. (λb false) true iszero =def λn.(λ b.false) true • The successor function succ n =def λf. λs. f (n f s) succ =def λn. λf. λs. f (n f s) • Addition add n1 n2 =def n1 succ n2 add =def λn1.λn2. n1 succ n2 • Multiplication mult n1 n2 =def n1 (add n2) 0 mult =def λn1.λn2. n1 (add n2) 0 Ex: Computing with Naturals mult 2 2 → 2 (add 2) 0 → (add 2) ((add 2) 0) → 2 succ (add 2 0) → 2 succ (2 succ 0) → succ (succ (succ (succ 0 0))) → succ (succ (succ (λf. λs. f (0 f s)))) → succ (succ (succ (λf. (λf λs. λs f s))) → succ (succ (λg. λy. g ((λf. λs. f s) g y))) → succ (succ (λg. λy. g (g y))) →* λg. λy. g (g (g (g y))) = 4 Ex: Computing with Naturals What is the result of add 0 ? (λn1. λn2. n1 succ n2) 0 →β λn2. 0 succ n2 = λn2. (λf. (λf λs. λs s) succ n2 →β λn2. n2 = λx. x λ Encoding Recursion • Write a function find that: takes “predicate” P, “natural” n, returns t smallest ll t nat., t larger l g th than n, satisfying ti f i g P • find can encode all recursion… • …but but how to write it ? Encoding Recursion The Y Y-Combinator Combinator find satisfies the equation: find p n = if p n then n else find p (succ n) Define: Y =def λF. (λy.F(y y)) (λx. F(x x)) • Called the fixpoint combinator because … • Define: F = λf.λp.λn.(p n) n (f p (succ n)) • A fixpoint of F is an x s.t. st x=Fx • find is a fixpoint of F ! – as find p n = F find p n – so find = F find Q: Given λ-term F, how to write its fixpoint ? – YF →β (λy.F (λ F (y ( y)) )) (λ (λx. F ((x x)) )) →β F ((λx.F (x x))(λz. F (z z))) β← F(YF) – i.e. Y F =β F (Y F) • Can write fixpoint for any λ λ-calculus calculus function • Define: F = λf.λp.λn.(p n) n (f p (succ n)) – find = Y F Whoa! Fixpoint Combinators Define: F = λf.λp.λn.(p n) n (f p (succ n)) and: find = Y F Y =def λF. (λy.F(y y)) (λx. F(x x)) Whats going on ? fi d p n find =β Y F p n =β F (Y F) p n =β F find p n =β (p n) n (find p (succ n)) How does this mix with Call-by-Value ? – YF →β (λy.F (y y)) (λx. F (x x)) →β F ((λx.F (x x))(λz. F (z z))) →β F (F ((λx.F (x x))(λz. F (z z)))) →β F (F (F ((λx.F ((λx F (x x))(λz. x))(λz F (z z))))) →β … Many other fixpoint combinators • Including those that work for CBV – See upcoming HW Including Klop’s Combinator: Expressiveness of λ λ-calculus calculus • Encodings are fun… fun … but programming in pure λ-calculus is not • Encodings complicate static analysis Yk =def (L L L L L L L L L L L L L L L L L L L L L L L L L L) where: L =def λaλbλcλdλeλfλgλhλIλjλkλlλmλnλoλpλqλsλtλuλvλwλxλyλzλr. r (t h i s i s a f i x p o i n t c o m b i n a t o r) • Know the λ-calculus encodes them, so we add 0,1,2,…,true,false,if-then-else 0 1 2 true false if then else to language • Next, N t we will ill add dd types… t
© Copyright 2026 Paperzz