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.