Lecture 13

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