(*<*) theory Lecture7 imports Main LaTeXsugar OptionalSugar begin (*>*) section "Case study: the simply typed lambda calculus" text{* We formalize an operational semantics for the simply typed lambda calculus in the evaluation context style~\cite{felleisen92:_seq_control,wright94:_type_soundness} and prove type safety. We use a relatively new approach for representing variables called ``locally nameless''~\cite{Chargueraud:2006uq,Gordon:1994kx,Pollack:1994vn}. In the locally nameless approach, bound variables are represented with de Bruijn indices whereas free variables are represented with symbols. This approach enjoys the benefits of the de Bruijn indices ($\alpha$-equivalent terms are syntactically identical) while avoiding much of the complication (normally caused by representing free variables with de Bruijn indices). Separate functions are used to substitution for free and bound variables. *} subsection "Syntax of the simply typed lambda calculus" datatype ty = IntT | BoolT | ArrowT ty ty (infixr "\" 200) datatype const = IntC int | BoolC bool | Succ | IsZero datatype expr = BVar nat | FVar nat | Const const | Lam ty expr ("\:_. _" [52,52] 51) | App expr expr text{* Free variables *} consts FV :: "expr \ nat set" primrec "FV (BVar i) = {}" "FV (FVar x) = {x}" "FV (Const c) = {}" "FV (\:\. e) = FV e" "FV (App e1 e2) = FV e1 \ FV e2" lemma finite_FV: "finite (FV e)" apply (induct e) by auto text{* Substitution for free variables *} consts fsubst :: "nat \ expr \ expr \ expr" ("[_\_]_" [54,54,54] 53) primrec "[z\e](BVar i) = BVar i" "[z\e](FVar x) = (if z = x then e else (FVar x))" "[z\e](Const c) = Const c" "[z\e](\:\. e') = (\:\. [z\e]e')" "[z\e](App e1 e2) = App ([z\e]e1) ([z\e]e2)" text{* Substitution for bound variables *} consts bsubst :: "nat \ expr \ expr \ expr" ("{_\_}_" [54,54,54] 53) primrec "{k\e}(BVar i) = (if k = i then e else (BVar i))" "{k\e}(FVar x) = FVar x" "{k\e}(Const c) = Const c" "{k\e}(\:\. e') = (\:\. {Suc k\e}e')" "{k\e}(App e1 e2) = App ({k\e}e1) ({k\e}e2)" subsection "Operational semantics with evaluation contexts" text{* A utility function for casting an arbitrary expression to an integer. *} consts to_int :: "expr \ int option" primrec "to_int (BVar x) = None" "to_int (FVar x) = None" "to_int (Const c) = (case c of IntC n \ Some n | BoolC b \ None | Succ \ None | IsZero \ None)" "to_int (Lam \ e) = None" "to_int (App e1 e2) = None" text{* The $\delta$ function evaluates the primitive operators. *} consts delta :: "const \ expr \ expr option" ("\") primrec "delta (IntC n) e = None" "delta (BoolC b) e = None" "delta Succ e = (case to_int e of None \ None | Some n \ Some (Const (IntC (n + 1))))" "delta IsZero e = (case to_int e of None \ None | Some n \ Some (Const (BoolC (n = 0))))" text{* Evaluation reduces expressions to values. The following is the definition of which expressions are values. *} consts Values :: "expr \ bool" primrec "Values (BVar i) = True" "Values (FVar x) = True" "Values (Const c) = True" "Values (\:\. e) = True" "Values (App e1 e2) = False" text{* The call-by-value notion of reduction is defined as follows. *} inductive reduces :: "expr \ expr \ bool" (infixl "-\" 51) where Beta: "Values v \ App (\:\. e) v -\ {0\v}e" | Delta: "\ \ c v = Some v'; Values v \ \ App (Const c) v -\ v'" constdefs redex :: "expr \ bool" "redex r \ (\ r'. r -\ r')" text{* We use contexts to specify where reduction can take place within an expression. *} datatype ctx = Hole | AppL ctx expr | AppR expr ctx inductive_set wf_ctx :: "ctx set" where WFHole: "Hole \ wf_ctx" | WFAppL: "E \ wf_ctx \ AppL E e \ wf_ctx" | WFAppR: "\ Values v; E \ wf_ctx \ \ AppR v E \ wf_ctx" consts fill :: "ctx \ expr \ expr" ("_[_]" [82,82] 81) primrec "Hole[e] = e" "(AppL E e2)[e] = App (E[e]) e2" "(AppR e1 E)[e] = App e1 (E[e])" inductive eval_step :: "expr \ expr \ bool" (infixl "\" 51) where Step: "\ E \ wf_ctx; r -\ r' \ \ E[r] \ E[r']" subsection "Creating fresh variables" constdefs max :: "nat \ nat \ nat" "max x y \ (if x < y then y else x)" declare max_def[simp] interpretation AC_max: ACe ["max" "0::nat"] by unfold_locales (auto intro: add_assoc add_commute) constdefs setmax :: "nat set \ nat" "setmax S \ fold max (\ x. x) 0 S" lemma max_ge: "finite L \ \ x \ L. x \ setmax L" apply (induct rule: finite_induct) apply simp apply clarify apply (case_tac "xa = x") proof - fix x and F::"nat set" and xa assume fF: "finite F" and xF: "x \ F" and xax: "xa = x" from fF xF have mc: "setmax (insert x F) = max x (setmax F)" apply (simp only: setmax_def) apply (rule AC_max.fold_insert) apply auto done with xax show "xa \ setmax (insert x F)" apply clarify by simp next fix x and F::"nat set" and xa assume fF: "finite F" and xF: "x \ F" and axF: "\x\F. x \ setmax F" and xsxF: "xa \ insert x F" and xax: "xa \ x" from xax xsxF have xaF: "xa \ F" by auto with axF have xasF: "xa \ setmax F" by blast from fF xF have mc: "setmax (insert x F) = max x (setmax F)" apply (simp only: setmax_def) apply (rule AC_max.fold_insert) apply auto done with xasF show "xa \ setmax (insert x F)" by auto qed lemma max_is_fresh[simp]: assumes F: "finite L" shows "Suc (setmax L) \ L" proof assume ssl: "Suc (setmax L) \ L" with F max_ge have "Suc (setmax L) \ setmax L" by blast thus "False" by simp qed lemma greaterthan_max_is_fresh[simp]: assumes F: "finite L" and I: "setmax L < i" shows "i \ L" proof assume ssl: "i \ L" with F max_ge have "i \ setmax L" by blast with I show "False" by simp qed subsection "Well-typed expressions" types env = "nat \ ty option" constdefs remove_bind :: "env \ nat \ env \ bool" ("_ - _ \ _" [50,50,50] 49) "\ - z \ \' \ \ x \. x \ z \ \ x = Some \ \ \' x = Some \" constdefs finite_env :: "env \ bool" "finite_env \ \ finite (dom \)" declare finite_env_def[simp] consts TypeOf :: "const \ ty" primrec "TypeOf (IntC n) = IntT" "TypeOf (BoolC b) = BoolT" "TypeOf Succ = IntT \ IntT" "TypeOf IsZero = IntT \ BoolT" inductive wte :: "env \ [expr,ty] \ bool" ("_ \ _ : _" [52,52,52] 51) where wte_var: "\ x = Some \ \ \ \ FVar x : \" | wte_const: "\ \ Const c : TypeOf c" | wte_abs: "\ finite L; dom \ \ L; \ x. x \ L \ \(x\\) \ {0\FVar x}e : \ \ \ \ \ (\:\. e) : \ \ \" | wte_app: "\ \ \ e1 : \ \ \; \ \ e2 : \ \ \ \ \ App e1 e2 : \" subsection "Properties of substitution" lemma bsubst_cross[rule_format]: "\ i j u v. i \ j \ {i\u}({j\v}t) = {j\v}t \ {i\u}t = t" apply (induct t) apply force apply force apply force apply clarify apply (erule_tac x="Suc i" in allE) apply (erule_tac x="Suc j" in allE) apply (erule_tac x=u in allE) apply (erule_tac x=v in allE) apply simp apply clarify apply (erule_tac x="i" in allE) apply (erule_tac x="i" in allE) apply (erule_tac x="j" in allE) apply (erule_tac x="j" in allE) apply simp apply blast done lemma bsubst_wt: "\ \ \ e : \; finite_env \ \ \ \ k e'. {k\e'}e = e" apply (induct rule: wte.induct) apply force apply force apply clarify apply simp apply (erule_tac x="Suc (setmax L)" in allE) apply (erule impE) apply (rule max_is_fresh) apply simp apply (erule conjE)+ apply (erule_tac x="Suc k" in allE) apply (erule_tac x="e'" in allE) apply (rule bsubst_cross) apply blast apply force done lemma subst_permute_impl[rule_format]: "\ j x z \ \ e'. x \ z \ \ \ e' : \ \ finite_env \ \ [z\e']({j\FVar x}e) = {j\ FVar x}([z\e']e)" apply (induct e) apply force apply simp apply clarify apply (frule bsubst_wt) apply simp apply (erule_tac x="j" in allE) apply (erule_tac x="FVar x" in allE) apply simp apply simp apply simp apply clarify apply blast apply simp apply clarify apply (erule_tac x="j" in allE) apply (erule_tac x="j" in allE) apply (erule_tac x="x" in allE) apply (erule_tac x="x" in allE) apply (erule_tac x="z" in allE) apply (erule_tac x="z" in allE) apply (erule_tac x="\" in allE) apply (erule_tac x="\" in allE) apply blast done lemma subst_permute: "\ x \ z; \ \ e' : \; finite_env \ \ \ {j\ FVar x}([z\e']e) = [z\e']({j\FVar x}e)" using subst_permute_impl[of x z \ e' \ j e] by simp lemma decompose_subst[rule_format]: "\ u x i. x \ FV e \ {i\u}e = [x\u]({i\FVar x}e)" apply (induct e) apply force apply force apply force apply clarify apply (erule_tac x=u in allE) apply (erule_tac x=x in allE) apply (erule_tac x="Suc i" in allE) apply simp apply force done subsection "Properties of environments and rule induction" constdefs subseteq :: "env \ env \ bool" (infixl "\" 80) "\ \ \' \ \ x \. \ x = Some \ \ \' x = Some \" lemma env_weakening: "\ \ e : \ \ \ \'. \ \ \' \ finite_env \' \ \' \ e : \" apply (induct rule: wte.induct) using subseteq_def wte_var apply blast using wte_const apply blast prefer 2 using wte_app apply blast apply (rule allI) apply (rule impI) proof - fix L::"nat set" and \::env and \ \ e \' assume fL: "finite L" and GL: "dom \ \ L" and IH: "\x. x \ L \ (\(x\\) \ {0\FVar x}e : \ \ (\\'. \(x\\) \ \' \ finite_env \' \ \' \ {0\FVar x}e : \))" and GGP: "\ \ \' \ finite_env \'" let ?L = "L \ dom \'" from GGP have "finite (dom \')" by auto with fL have fL2: "finite ?L" by auto { fix x assume xL: "x \ ?L" from GGP have xGxGP: "\(x\\) \ \'(x\\)" using subseteq_def by auto from GGP have fGP: "finite_env (\'(x\\))" by auto from xL fGP IH xGxGP have "\'(x\\) \ {0\FVar x}e : \" by blast } hence X: "\ x. x \ ?L \ \'(x\\) \ {0\FVar x}e : \" by blast have dGL: "dom \' \ ?L" by auto from fL2 dGL X show "\' \ (\:\. e) : \ \ \" by (rule wte_abs) qed subsection "The substition lemma" lemma substitution: "\ \ \ e1 : \; \ x = Some \; finite_env \ \ \ (\ \'. finite_env \' \ \ - x \ \' \ \' \ e2 : \ \ \' \ [x\e2]e1 : \)" (is "\ \ \ e1 : \; \ x = Some \; finite_env \ \ \ ?P \ e1 \ x \") apply (induct rule : wte.induct) apply (case_tac "x = xa") apply simp apply clarify apply (simp only: remove_bind_def) apply (erule_tac x=xa in allE) apply simp apply (rule wte_var) apply assumption using wte_const apply force prefer 2 apply clarify apply simp apply (rule wte_app) apply blast apply blast proof clarify fix L::"nat set" and \::env and \'::ty and \ e \' assume fL: "finite L" and "dom \ \ L" and IH: "\xa. xa \ L \ (\(xa \ \') \ {0\FVar xa}e : \ \ ((\(xa \ \')) x = Some \ \ finite_env (\(xa \ \')) \ (?P (\(xa \ \')) ({0\FVar xa}e) \ x \)))" and xG: " \ x = Some \" and fG: "finite_env \" and fGP: "finite_env \'" and GxG: "\ - x \ \'" and wte2: "\' \ e2 : \" let ?L = "insert x (L \ dom \ \ dom \')" show "\' \ [x\e2](\:\'. e) : \' \ \" proof simp show "\' \ (\:\'. [x\e2]e) : \' \ \" proof (rule wte_abs[of "?L"]) from fL fG fGP show "finite ?L" by auto next show "dom \' \ ?L" by auto next show "\xa. xa \ ?L \ \'(xa \ \') \ {0\FVar xa}([x\e2]e) : \" proof (rule allI, rule impI) fix x' assume xL: "x' \ ?L" let ?GP = "\'(x'\\')" from xL fGP wte2 have wte2b: "?GP \ e2 : \" using subseteq_def env_weakening by force from xG xL wte2b fG fGP GxG IH have wte: "?GP \ [x\e2]({0\FVar x'}e) : \" using remove_bind_def by auto from xL wte2b fGP have "{0\FVar x'}([x\e2]e) = [x\e2]({0\FVar x'}e)" using subst_permute by auto with wte xL show "?GP \ {0\FVar x'}([x\e2]e) : \" by auto qed qed qed qed subsection "Inversion rules and canonical forms" text{* We use Isabelle's \textbf{inductive-cases} form to generate inversion rules for expressions with certain types, such as integers and functions. These rules are called ``inversion'' rules because they let you use the inductive definitions in reverse, going from the conclusions to the premises. *} inductive_cases wte_int_inv: "empty \ e : IntT" text{* \noindent From the above, Isabelle generates {\scriptsize \begin{equation} @{thm [mode=Rule] wte_int_inv[no_vars]} \notag \end{equation} } *} inductive_cases wte_fun_inv: "empty \ e : \ \ \" text{* \noindent and Isabelle generates {\scriptsize \begin{equation} @{thm [mode=Rule] wte_fun_inv[no_vars]} \notag \end{equation} } *} text{* The following canonical forms lemmas describe what kinds of \emph{values} have certain types. For example, the only value that has type \textit{IntT} is an integer constant. The canonical forms lemmas are needed to prove subject reduction. *} lemma canonical_form_int: assumes eint: "empty \ e : IntT" and ve: "Values e" shows "\ n. e = Const (IntC n)" using eint apply (rule wte_int_inv) using ve apply auto apply (case_tac c) by auto lemma canonical_form_fun: assumes wtf: "empty \ v : \ \ \" and v: "Values v" shows "(\ e. v = \:\. e) \ (\ c. v = Const c)" using wtf apply (rule wte_fun_inv) using v by auto subsection "Subject reduction" lemma delta_typability: assumes tc: "TypeOf c = \' \ \" and vt: "empty \ v : \'" and vv: "Values v" shows "\ v'. \ c v = Some v' \ empty \ v' : \" using tc vt vv apply (cases c) apply simp apply simp proof - assume tc: "TypeOf c = \' \ \" and vt: "empty \ v : \'" and vv: "Values v" and c: "c = Succ" from c tc have st: "\' = IntT \ \ = IntT" by simp from st vt vv obtain n where v: "v = Const (IntC n)" apply simp using canonical_form_int by blast let ?VP = "Const (IntC (n + 1))" have wtvp: "empty \ ?VP : IntT" using wte_const[of empty "IntC (n + 1)"] by auto from c v have d: "\ c v = Some ?VP" by simp from d wtvp st show ?thesis by simp next assume tc: "TypeOf c = \' \ \" and vt: "empty \ v : \'" and vv: "Values v" and c: "c = IsZero" from c tc have st: "\' = IntT \ \ = BoolT" by simp from st vt vv obtain n where v: "v = Const (IntC n)" apply simp using canonical_form_int by blast let ?VP = "Const (BoolC (n = 0))" have wtvp: "empty \ ?VP : BoolT" using wte_const[of empty "BoolC (n = 0)"] by auto from c v have d: "\ c v = Some ?VP" by simp from d wtvp st show ?thesis by simp qed lemma subject_reduction: assumes wte: "\ \ e : \" and g: "\ = empty" and red: "e -\ e'" shows "empty \ e' : \" using wte g red apply (cases rule: wte.cases) apply simp_all apply (cases rule: reduces.cases) apply simp+ apply (cases rule: reduces.cases) apply simp+ apply clarify proof - -- "Beta" fix \::env and \ \' e1 e2 assume wte1: "empty \ e1 : \ \ \" and wte2: "empty \ e2 : \" and red: "App e1 e2 -\ e'" -- "Would be cleaner to use an inductive cases for the above 'red'" from red show "empty \ e' : \" proof (cases rule: reduces.cases) fix v \'' b assume a: "App e1 e2 = App (\:\''. b) v" and ep: "e' = {0\v}b" and vv: "Values v" have fe: "finite {}" by simp have xL: "(0::nat) \ {}" by simp from wte1 fe a xL obtain L where fL: "finite L" and wtb: "\x. x \ L \ [x \ \] \ {0\FVar x}b : \" apply (cases rule: wte.cases) by auto let ?X = "Suc (max (setmax L) (setmax (FV b)))" have xgel: "setmax L < ?X" by auto have xgeb: "setmax (FV b) < ?X" by auto -- "Set up for and apply the substitution lemma" from fL xgel have xL: "?X \ L" by (rule greaterthan_max_is_fresh) with wtb have wtb2: "[?X \ \] \ {0\FVar ?X}b : \" by blast have gxs: "[?X \ \] ?X = Some \" by simp have fg: "finite_env [?X \ \]" by simp have fgp: "finite_env empty" by simp have gxgp: "[?X \ \] - ?X \ empty" by (simp add: remove_bind_def) from wtb2 gxs fg fgp gxgp wte2 have wtb: "empty \ [?X\e2]({0\FVar ?X}b) : \" using substitution by blast -- "Use the substitution decomposition lemma" have finb: "finite (FV b)" by (rule finite_FV) from finb xgeb have xb: "?X \ FV b" by (rule greaterthan_max_is_fresh) from xb have "{0\e2}b = [?X\e2]({0\FVar ?X}b)" by (rule decompose_subst) with wtb a ep show "empty \ e' : \" by simp next -- "Delta" fix c v v' assume a: "App e1 e2 = App (Const c) v" and ep: "e' = v'" and d: "\ c v = Some v'" and vv: "Values v" from wte1 a have tc: "TypeOf c = \ \ \" apply (cases rule: wte.cases) by auto from a tc wte2 vv obtain v'' where dd: "\ c v = Some v''" and wtvp: "empty \ v'' : \" using delta_typability by blast from wtvp a ep d dd show "empty \ e' : \" by simp qed qed subsection "Decomposition" inductive welltyped_ctx :: "env \ ctx \ ty \ ty \ bool" ("_ \ _ : _\_" [52,52,52,52] 51) where WTHole: "\ \ Hole : \ \ \" | WTAppL: "\ \ \ E : \ \ (\ \ \); \ \ e : \ \ \ \ \ AppL E e : \ \ \" | WTAppR: "\ \ \ e : \ \ \; \ \ E : \ \ \ \ \ \ \ AppR e E : \ \ \" lemma welltyped_decomposition: "\ \ e : \ \ \ = empty \ Values e \ (\ \ E r. e = E[r] \ \ \ E : \ \ \ \ E \ wf_ctx \ \ \ r : \ \ redex r)" (is "\ \ e : \ \ ?P \ e \") apply (induct rule: wte.induct) apply simp apply simp apply simp apply (rule impI) proof - fix \ e1 \ \ e2 assume wte1: "\ \ e1 : \ \ \" and IH1: "?P \ e1 (\\\)" and wte2: "\ \ e2 : \" and IH2: "?P \ e2 \" and g: "\ = empty" show "Values (App e1 e2) \ (\\ E r. App e1 e2 = E[r] \ \ \ E : \\\ \ E \ wf_ctx \ \ \ r : \ \ redex r)" proof (cases "Values e1") assume ve1: "Values e1" show "?thesis" proof (cases "Values e2") assume ve2: "Values e2" have h: "App e1 e2 = Hole[App e1 e2]" by simp have wth: "empty \ Hole : \\\" by (rule WTHole) from wte1 wte2 g have wta: "empty \ App e1 e2 : \" apply simp by (rule wte_app) from wte1 ve1 g have "(\ e. e1 = \:\. e) \ (\ c. e1 = Const c)" apply simp apply (rule canonical_form_fun) by auto moreover { assume x: "\ e. e1 = \:\. e" -- "Beta" from x obtain b where e1: "e1 = \:\. b" by blast from e1 ve2 have "App e1 e2 -\ {0\e2}b" apply simp by (rule Beta) hence r: "redex (App e1 e2)" using redex_def by blast have wfh: "Hole \ wf_ctx" by (rule WFHole) from h wth wfh wta r g have "?thesis" by blast } moreover { assume x: "\ c. e1 = Const c" -- "Delta" from x obtain c where e1: "e1 = Const c" by blast from wte1 e1 have tc: "TypeOf c = \ \ \" apply (cases rule: wte.cases) by auto from tc wte2 ve2 g obtain v'' where dd: "\ c e2 = Some v''" using delta_typability by blast from dd ve2 e1 have "App e1 e2 -\ v''" apply simp by (rule Delta) hence r: "redex (App e1 e2)" using redex_def by blast have wfh: "Hole \ wf_ctx" by (rule WFHole) with h wth wfh wta r g have "?thesis" by blast } ultimately show ?thesis by blast next assume ve2: "\ Values e2" from ve2 IH2 g obtain \' and E::ctx and r where e2: "e2 = E[r]" and wtE: "\ \ E : \'\\" and wfE: "E \ wf_ctx" and wtr: "\ \ r : \'" and rr: "redex r" by blast from e2 have "App e1 e2 = (AppR e1 E)[r]" by simp moreover from wte1 wtE g have "empty \ AppR e1 E : \' \ \" apply simp apply (rule WTAppR) apply auto done moreover from ve1 wfE have "AppR e1 E \ wf_ctx" by (rule WFAppR) moreover note wtr rr g ultimately show ?thesis by blast qed next assume ve1: "\ Values e1" from ve1 IH1 g obtain \' and E::ctx and r where e1: "e1 = E[r]" and wtE: "\ \ E : \'\\\\" and wfE: "E \ wf_ctx" and wtr: "\ \ r : \'" and rr: "redex r" by blast from e1 have "App e1 e2 = (AppL E e2)[r]" by simp moreover from wtE wte2 g have "empty \ AppL E e2 : \' \ \" apply simp apply (rule WTAppL) apply auto done moreover from wfE have "AppL E e2 \ wf_ctx" by (rule WFAppL) moreover note wtr rr g ultimately show ?thesis by blast qed qed lemma welltyped_expr_ctx_impl: "\ \ e : \ \ \ E r. e = E[r] \ (\ \. \ \ E : \ \ \ \ \ \ r : \)" apply (induct rule: wte.induct) apply clarify apply (rule_tac x="\" in exI) apply (case_tac E) using wte_var WTHole apply force apply simp apply simp apply clarify apply (rule_tac x="TypeOf c" in exI) apply (case_tac E) using wte_const WTHole apply force apply simp apply simp apply clarify apply (case_tac E) apply (rule_tac x="\\\" in exI) apply simp using wte_abs WTHole apply force apply simp apply simp apply clarify apply (case_tac E) apply (rule_tac x="\" in exI) using wte_app WTHole apply force apply (erule_tac x=ctx in allE) apply (erule_tac x=ctx in allE) apply (erule_tac x=r in allE) apply (erule_tac x=r in allE) apply simp using WTAppL apply blast apply (erule_tac x=ctx in allE) apply (erule_tac x=ctx in allE) apply (erule_tac x=r in allE) apply (erule_tac x=r in allE) apply simp using WTAppR apply blast done lemma welltyped_expr_ctx: "\ \ E[r] : \ \ \ \. \ \ E : \ \ \ \ \ \ r : \" using welltyped_expr_ctx_impl by simp lemma fill_ctx_welltyped[rule_format]: "\ \ E : \ \ \ \ \ r. \ \ r : \ \ \ \ E[r] : \" apply (induct rule: welltyped_ctx.induct) apply simp using wte_app apply force using wte_app apply force done subsection "Progress and preservation" lemma progress: assumes wte: "empty \ e : \" shows "Values e \ (\ e'. e \ e')" proof - show ?thesis proof (cases "Values e") assume "Values e" thus ?thesis by simp next assume "\ Values e" with wte have x: "\ \ E r. e = E[r] \ empty \ E : \ \ \ \ E \ wf_ctx \ empty \ r : \ \ redex r" using welltyped_decomposition[of empty e \] by simp from x obtain \ and E::ctx and r where eE: "e = E[r]" and wtc: "empty \ E : \ \ \" and wfE: "E \ wf_ctx" and wtr: "empty \ r : \" and rr: "redex r" by blast from rr obtain r' where red: "r -\ r'" using redex_def by blast from wfE red have "E[r] \ E[r']" by (rule Step) with eE show ?thesis by blast qed qed lemma preservation: assumes s: "e \ e'" and wte: "empty \ e : \" shows "empty \ e' : \" using s proof (cases rule: eval_step.cases) fix E::ctx and r r' assume a: "e = E[r]" and ep: "e' = E[r']" and wfE: "E \ wf_ctx" and rr: "r -\ r'" from a wte obtain \ where wtc: "empty \ E : \ \ \" and wtr: "empty \ r : \" using welltyped_expr_ctx by blast from wtr rr have wtrp: "empty \ r' : \" using subject_reduction by blast from wtc wtrp have "empty \ E[r'] : \" by (rule fill_ctx_welltyped) with a ep show ?thesis by simp qed subsection "Type safety" constdefs finished :: "expr \ bool" "finished e \ \(\ e'. e \ e')" inductive ref_tran_cl :: "('a \ 'a \ bool) \ ('a \ 'a \ bool)" ("(_^*)" [1000] 999) for r :: "'a \ 'a \ bool" where ref_tran_cl_refl [intro!, Pure.intro!, simp]: "(r^*) a a" | ref_tran_cl_into_ref_tran_cl [Pure.intro]: "(r^*) a b ==> r b c ==> (r^*) a c" abbreviation eval_step_ref_tran_cl :: "expr \ expr \ bool" (infixl "\\<^sup>*" 51) where "e \\<^sup>* e' \ (eval_step^*) e e'" theorem type_safety: assumes et: "empty \ e : \" and ee: "e \\<^sup>* e'" shows "empty \ e' : \ \ (Values e' \ \ (finished e'))" using ee et proof (induct rule: ref_tran_cl.induct) fix a assume wta: "empty \ a : \" from wta have "Values a \ (\ e'. a \ e')" by (rule progress) with wta show "empty \ a : \ \ (Values a \ \ (finished a))" using finished_def by auto next fix a b c assume IH: "empty \ a : \ \ empty \ b : \ \ (Values b \ \(finished b))" and bc: "b \ c" and wta: "empty \ a : \" from wta IH have wtb: "empty \ b : \" by simp from bc wtb have wtc: "empty \ c : \" by (rule preservation) from wtc have "Values c \ (\ e'. c \ e')" by (rule progress) with wtc show "empty \ c : \ \ (Values c \ \ (finished c))" using finished_def by auto qed (*<*) end (*>*)