Evaluation Contexts
-------------------
Motivation: A concise notation for communicating operational rules.
The language with simplified operational semantics:
t ::= bool | t1 -> t2
e ::= x | v | if e1 then e2 else e3 | e1 e2
v ::= true | false | \x:t.e
E ::= [] | E e | v E | if E then e1 else e2
If E is an evaluation context then E[e] is the expression that results from
replacing the [] inside E with e. The following equations define "plugging the
hole" in E with e. In general, the equations have the form E[e] = e'. There
is one equation for each different kind of context E.
[][e] = e
(E' e')[e] = (E'[e]) e'
(v E')[e] = v (E'[e])
(if E then e1 else e2)[e] = if E[e] then e1 else e2
The above definition of E eliminates the need to include a number of
"search rules" from the original semantics and hence makes the semantics
more compact. Here is the complete set of evaluation rules:
Evaluation rules:
---------------------
(\x:t.e) v -> e[v/x]
----------------------------- ------------------------------
if true then e1 else e2 -> e1 if false then e1 else e2 -> e2
e -> e'
-------------- (E-context)
E[e] -> E[e']
The E-context rule replaces all of the search rules all at once. Notice
how the evaluation contexts E relates to the old evaluation rules (not using
contexts):
E e corresponds to
e1 -> e1'
---------------
e1 e2 -> e1' e2
v E corresponds to
e2 -> e2'
---------------
v e2 -> v e2'
(if E then e2 else e3) corresponds to
e1 -> e1'
------------------------
if e1 then e2 else e3 ->
if e1' then e2 else e3
To see how the rule E-context works, suppose we have an expression
that looks like this:
if (\x:bool.x) ((\x:bool.x) true) then false else true
We can break that expression down into E1[e1] if we
let E1 = (if (\x:bool.x) [] then false else true)
and e1 = ((\x:bool.x) true)
Notice that according to our normal rule for function application, we have:
e1 -> true
Now, we have according to (E-context):
e1 -> true
----------------
E1[e1] -> E1[true]
In other words, we have:
if (\x:bool.x) ((\x:bool.x) true) then false else true ->
if (\x:bool.x) true then false else true
Preservation Lemma:
-------------------
If |- e : t and e -> e', then |- e' : t
Proof: By induction on the derivation of e -> e'
Case:
e -> e'
-----------------
E[e] -> E[e']
Given that |- E[e] : t,
must prove that |- E[e'] : t
How do we do that? We need some additional lemmas.
Typing Evaluation Contexts
--------------------------
We define a typing rule for eval context:
G, x : t1 |- E[x] : t2
----------------------- (T-context)
G |- E : t1 ==> t2
Lemma 1. If |- E[e] : t2 then there exists a type t1, such that
x: t1 |- E[x] : t2 and |- e : t1
Proof: By induction on the structure of E
Case: E = []
(1) |- [][e] : t2 (by assumption)
(2) |- e : t2 (the same as (1) by definition of "plugging the hole")
(3) x:t2 |- x : t2 (by the standard variable typing rule)
(4) x:t2 |- [][x] : t2 (the same as (3) by definition of "plugging the hole")
By (2) and (5), we have what we needed to prove. Namely, that there exists
a type t1 (in this case that type is the same as t2), such that
|- e : t1 and x:t1 |- [][x] : t2
Case Done.
Case: E = E e
[[[
Note, in order to do this case, we need to remember what the application
typing rule looks like. It looks like this:
Gamma |- e1 : t_arg -> t2 Gamma |- e2 : t_arg
-------------------------------------------------
Gamma |- e1 e2 : t2
We also need to use the weakening lemma, which looks like this:
If Gamma |- e : t and x not in Dom(Gamma) then Gamma,x:t' |- e : t.
]]]
(1) |- (E1 e1)[e] : t2 (by assumption)
(2) |- (E1[e]) e1 : t2 (same as (1) by def of hole-plugging)
(3) |- (E1[e]) : t_arg -> t2 (by (2) and inversion of application typing rule)
(4) |- e1 : t_arg (by (2) inversion of application typing rule)
(5) x: t1 |- e1 : t_arg (by (4) and weakening form lemma)
(6) x: t1 |- E1[x] : t_arg -> t2 (by (3) and I.H.)
(7) |- e : t1 (by (3) and I.H.)
(8) x: t1 | (E1[x]) e1 : t2 (by (5) and (6) and application typing rule)
By (7) and (8) we have proved what we needed to and are done with this case.
Case Done.
Case E = v E' --- similar to case for E e
Case if E then e1 else e2 --- similar to case for E e, except the typing rules for if statements
are used in the proof instead of the typing rules for application)
----------
Corollary 1. If |- E[e] : t2 then there exists a type t1, such that
|- E: t1 ==> t2 and |- e : t1
Proof: follows immediately from Lemma 1 and T-context rule.
Lemma 2. if G |- E : t1 ==> t2, and G |- e : t1 then
G |- E[e] : t2
Proof: It is a proof by induction on the structure of E, so there is one case
for each different kind of E. Try it as an exercise.
Preservation Theorem: if |- e : t and e -> e' then |- e' : t
Case:
(1) e1 -> e1'
----------------- (Note: e = E[e1] and e' = E[e1'])
E[e1] -> E[e1']
(2) |- E[e1] : t (Assumption)
(3) |- e1 : t1 (By (2) and Corollary 1)
(4) |- E : t1 ==> t (By (2) and Corollary 1)
(5) |- e1' : t1 (1, 3 and IH)
(6) |- E[e1'] : t (4, 5 and Lemma 2)
Other cases are similar to our previous type preservation proofs.
End Proof.
Decomposition Lemma:
If |- e: t then either
(1) e is a value v or
(2) e is one of the following forms:
(a) e = E[e'] and e' = (\x: t. e'') v
(b) e = E[e'] and e' = if true then e1 else e2
(c) e = E[e'] and e' = if false then e1 else e2
Proof: By induction on the derivation of |- e : t. (cases omitted. Sorry!)
End Proof.
Progress Theorem: if |- e : t then e is a value v or e -> e'
Proof: By decomposition, e is either a value or case 2a, 2b or 2c applies.
Case 1: e = v, case proved trivially
Case 2a: e = E[e'] and e' = (\x: t.e'') v
By E-Context rule:
(\x:t.e'') v -> e''[v/x]
-----------------------------
E[(\x:t.e'') v] -> E[e''[v/x]]
Therefore e -> e'
Cases 2b and 2c follows similarly using Rules If-true and If-false.
End Proof.