section {* Nominal implementation in Isabelle *}
theory LamYNom
imports "Nominal2-Isabelle/Nominal/Nominal2" begin
subsection {* Definition of $\lamy$ terms *}
atom_decl name
nominal_datatype type = O | Arr type type ("_ → _")
nominal_datatype trm =
Var name
| App trm trm
| Lam x::name l::trm binds x in l ("Lam [_]. _" [100, 100] 100)
| Y type
subsection {* Definition of substitution *}
nominal_function
subst :: "trm ⇒ name ⇒ trm ⇒ trm" ("_ [_ ::= _]" [90, 90, 90] 90)
where
"(Var x)[y ::= s] = (if x = y then s else (Var x))"
| "(App t1 t2)[y ::= s] = App (t1[y ::= s]) (t2[y ::= s])"
| "atom x ♯ (y, s) ⟹ (Lam [x]. t)[y ::= s] = Lam [x].(t[y ::= s])"
| "(Y t)[y ::= s] = Y t"
apply(simp add: eqvt_def subst_graph_aux_def)
apply(rule TrueI)
using [[simproc del: alpha_lst]]
apply(auto)
apply(rule_tac y="a" and c="(aa, b)" in trm.strong_exhaust)
apply(blast)+
apply(simp_all add: fresh_star_def fresh_Pair_elim)
apply (erule_tac c="(ya,sa)" in Abs_lst1_fcb2)
apply(simp_all add: Abs_fresh_iff)
apply(simp add: fresh_star_def fresh_Pair)
apply(simp only: eqvt_at_def)
apply(simp)
apply(simp add: fresh_star_Pair perm_supp_eq)
apply(simp only: eqvt_at_def)
apply(perm_simp)
apply(simp)
apply(simp add: fresh_star_Pair perm_supp_eq)
done
nominal_termination (eqvt)
by lexicographic_order
lemma forget:
shows "atom x ♯ t ⟹ t[x ::= s] = t"
by (nominal_induct t avoiding: x s rule: trm.strong_induct)
(auto simp add: fresh_at_base)
lemma fresh_type:
fixes n :: name and t :: type
shows "atom n ♯ t"
by (nominal_induct t rule:type.strong_induct, auto)
lemma fresh_fact:
fixes z::"name"
assumes a: "atom z ♯ s"
and b: "z = y ∨ atom z ♯ t"
shows "atom z ♯ t[y ::= s]"
using a b
apply (nominal_induct t avoiding: z y s rule: trm.strong_induct)
by (auto simp add:fresh_type)
lemma substitution_lemma:
assumes a: "x ≠ y" "atom x ♯ u"
shows "t[x ::= s][y ::= u] = t[y ::= u][x ::= s[y ::= u]]"
using a
by (nominal_induct t avoiding: x y s u rule: trm.strong_induct)
(auto simp add: fresh_fact forget)
subsection {*$\beta Y$-reduction*}
inductive
beta_Y :: "trm ⇒ trm ⇒ bool" (" _ ⇒ _" [80,80] 80)
where
red_L[intro]: "⟦ M ⇒ M' ⟧ ⟹ App M N ⇒ App M' N"
| red_R[intro]: "⟦ N ⇒ N' ⟧ ⟹ App M N ⇒ App M N'"
| abs[intro]: "⟦ M ⇒ M' ⟧ ⟹ Lam [x]. M ⇒ Lam [x]. M'"
| beta[intro]: "⟦ atom x ♯ N ⟧ ⟹ App (Lam [x]. M) N ⇒ M[x ::= N]"
| Y[intro]: "App (Y σ) M ⇒ App M (App (Y σ) M)"
equivariance beta_Y
nominal_inductive beta_Y
avoids beta: "x" | abs: "x"
by (simp_all add: fresh_star_def fresh_Pair fresh_fact fresh_type)
subsection {* Parallel $\beta Y$-reduction *}
inductive
pbeta :: "trm ⇒ trm ⇒ bool" ("_ ≫ _" [80,80] 80)
where
refl[intro]: "(Var x) ≫ (Var x)"
| reflY[intro]: "Y σ ≫ Y σ"
| app[intro]: "⟦ M ≫ M' ; N ≫ N' ⟧ ⟹ App M N ≫ App M' N'"
| abs[intro]: "⟦ M ≫ M' ⟧ ⟹ Lam [x]. M ≫ Lam [x]. M'"
| beta[intro]: "⟦ atom x ♯ N ; atom x ♯ N' ; M ≫ M' ; N ≫ N' ⟧ ⟹ App (Lam [x]. M) N ≫ M'[x ::= N']"
| Y[intro]: "⟦ M ≫ M' ⟧ ⟹ App (Y σ) M ≫ App M' (App (Y σ) M')"
equivariance pbeta
nominal_inductive pbeta
avoids beta: "x" | abs: "x"
by (simp_all add: fresh_star_def fresh_Pair fresh_fact fresh_type)
subsection {* Maximal parallel $\beta Y$-reduction *}
nominal_function
not_abst :: "trm ⇒ bool"
where
"not_abst (Var x) = True"
| "not_abst (App t1 t2) = True"
| "not_abst (Lam [x]. t) = False"
| "not_abst (Y t) = True"
apply (simp add: eqvt_def not_abst_graph_aux_def)
apply (rule TrueI)
apply (rule_tac y="x" in trm.exhaust)
using [[simproc del: alpha_lst]]
by auto
nominal_termination (eqvt) by lexicographic_order
nominal_function
not_Y :: "trm ⇒ bool"
where
"not_Y (Var x) = True"
| "not_Y (App t1 t2) = True"
| "not_Y (Lam [x]. t) = True"
| "not_Y (Y t) = False"
apply (simp add: eqvt_def not_Y_graph_aux_def)
apply (rule TrueI)
apply (rule_tac y="x" in trm.exhaust)
using [[simproc del: alpha_lst]]
by auto
nominal_termination (eqvt) by lexicographic_order
inductive
pbeta_max :: "trm ⇒ trm ⇒ bool" ("_ >>> _" [80,80] 80)
where
refl[intro]: "(Var x) >>> (Var x)"
| reflY[intro]: "Y σ >>> Y σ"
| app[intro]: "⟦ not_abst M ; not_Y M ; M >>> M' ; N >>> N' ⟧ ⟹ App M N >>> App M' N'"
| abs[intro]: "⟦ M >>> M' ⟧ ⟹ Lam [x]. M >>> Lam [x]. M'"
| beta[intro]: "⟦ atom x ♯ N ; atom x ♯ N' ; M >>> M' ; N >>> N' ⟧ ⟹ App (Lam [x]. M) N >>> M'[x ::= N']"
| Y[intro]: "⟦ M >>> M' ⟧ ⟹ App (Y σ) M >>> App M' (App (Y σ) M')"
equivariance pbeta_max
nominal_inductive pbeta_max
avoids beta: "x" | abs: "x"
by (simp_all add: fresh_star_def fresh_Pair fresh_fact fresh_type)
lemma not_Y_ex: "¬(not_Y M) ⟹ ∃σ. M = Y σ"
apply (cases M rule:not_Y.cases)
by auto
subsection {* \cref{Lemma:maxEx} *}
lemma pbeta_max_ex:
fixes M
shows "∃M'. M >>> M'"
apply (induct M rule:trm.induct)
apply auto
apply (case_tac "not_abst trm1")
apply (case_tac "not_Y trm1")
apply auto[1]
proof goal_cases
case (1 P Q P' Q')
then obtain σ where 2: "P = Y σ" using not_Y_ex by auto
have "App (Y σ) Q >>> App Q' (App (Y σ) Q')"
apply (rule_tac pbeta_max.Y)
by (rule 1(2))
thus ?case unfolding 2 by auto
next
case (2 P Q P' Q')
thus ?case
apply (nominal_induct P P' avoiding: Q Q' rule:pbeta_max.strong_induct)
by auto
qed
subsection {* \cref{Lemma:maxClose} *}
lemma subst_rename:
assumes a: "atom y ♯ t"
shows "t[x ::= s] = ((y ↔ x) ∙ t)[y ::= s]"
using a
apply (nominal_induct t avoiding: x y s rule: trm.strong_induct)
apply (auto simp add: fresh_at_base)
by (simp add: flip_fresh_fresh fresh_type)
lemma fresh_in_pbeta: "s ≫ s' ⟹ atom (x::name) ♯ s ⟹ atom x ♯ s'"
apply (nominal_induct s s' rule:pbeta.strong_induct)
apply simp
apply simp
apply auto[1]
proof goal_cases
case 1 thus ?case by auto
next
case (2 xx N N' M M')
then have "atom x ♯ N'" by simp
{ assume "x = xx" with 2 have ?case by (simp add: fresh_fact) }
{ assume "x ≠ xx" with 2 have ?case by (simp add: fresh_fact) }
thus ?case using ‹x = xx ⟹ atom x ♯ M' [xx ::= N']› by blast
next
case 3 thus ?case by simp
qed
lemma pbeta_lam_case_ex: "(Lam [x]. s) ≫ s' ⟹ ∃t. s' = Lam [x]. t ∧ s ≫ t"
proof (cases "(Lam [x]. s)" s' rule:pbeta.cases, simp)
case (goal1 _ _ x')
then have 1: "s ≫ ((x' ↔ x) ∙ M')" using pbeta.eqvt by (metis Abs1_eq_iff(3) Nominal2_Base.swap_self add_flip_cancel flip_commute flip_def permute_flip_cancel2 permute_plus)
from goal1 have 2: "(x' ↔ x) ∙ s' = Lam [x]. ((x' ↔ x) ∙ M')" by simp
from goal1 have "atom x ♯ (Lam [x']. M')" using fresh_in_pbeta by (meson trm.fresh(3) list.set_intros(1))
with 2 have "s' = Lam [x]. ((x' ↔ x) ∙ M')" unfolding goal1 by (metis "2" flip_fresh_fresh goal1(3) trm.fresh(3) list.set_intros(1))
with 1 show ?case by auto
qed
lemma pbeta_cases_2:
shows "atom x ♯ t ⟹ App (Lam [x]. s) t ≫ a2 ⟹
(⋀s' t'. a2 = App (Lam [x]. s') t' ⟹ atom x ♯ t' ⟹ s ≫ s' ⟹ t ≫ t' ⟹ P) ⟹
(⋀t' s'. a2 = s' [x ::= t'] ⟹ atom x ♯ t ⟹ atom x ♯ t' ⟹ s ≫ s' ⟹ t ≫ t' ⟹ P) ⟹ P"
apply atomize_elim
proof (cases "App (Lam [x]. s) t" a2 rule:pbeta.cases, simp)
case goal1
then obtain s'' where 1: "M' = Lam [x]. s''" "s ≫ s''" using pbeta_lam_case_ex by blast
thus ?case using goal1 fresh_in_pbeta by auto
next
case (goal2 xx _ ss)
have 1: "M' [xx ::= N'] = ((x ↔ xx) ∙ M') [x ::= N']"
by (metis (no_types, lifting) Abs1_eq_iff(3) Nominal2_Base.swap_self add_flip_cancel flip_def fresh_in_pbeta goal2(3) goal2(7) permute_flip_cancel permute_plus subst_rename)
from goal2 have 2: "s ≫ ((x ↔ xx) ∙ M')"
by (metis Abs1_eq_iff(3) Nominal2_Base.swap_self add_flip_cancel flip_def pbeta.eqvt permute_flip_cancel permute_plus)
from goal2 have 3: "atom x ♯ N'" using fresh_in_pbeta by simp
with goal2 1 2 show ?case by auto
qed
lemma Lem2_5_1:
assumes "s ≫ s'"
and "t ≫ t'"
shows "(s[x ::= t]) ≫ (s'[x ::= t'])"
using assms proof (nominal_induct s s' avoiding: x t t' rule:pbeta.strong_induct)
case (refl s)
then show ?case by auto
next
case (reflY s)
then show ?case by auto
next
case app
show ?case
unfolding subst.simps
apply (rule pbeta.app)
using app
by simp+
next
case (abs p p' y)
show ?case
apply (subst subst.simps)
using abs apply simp
apply (subst subst.simps)
using abs apply simp
apply (rule_tac pbeta.abs)
using abs by simp
next
case (beta y q q' p p')
have "App ((Lam [y]. p) [x ::= t]) (q [x ::= t]) ≫ (p' [x ::= t'])[y ::= q'[x ::= t']]"
apply (subst subst.simps(3))
defer
apply (rule_tac pbeta.beta)
using beta by (simp add: fresh_fact)+
then show ?case unfolding subst.simps
apply (subst substitution_lemma)
using beta by (simp add: fresh_fact)+
next
case (Y M M' σ)
show ?case unfolding subst.simps
apply (rule_tac pbeta.Y)
using Y by simp
qed
lemma pbeta_max_closes_pbeta:
fixes a b d
assumes "a >>> d"
and "a ≫ b"
shows "b ≫ d"
using assms proof (nominal_induct arbitrary: b rule:pbeta_max.strong_induct)
case (refl a)
show ?case using refl pbeta.cases by fastforce
next
case (reflY a) then have 1: "b = Y a" apply (cases rule: pbeta.cases) by simp
show ?case unfolding 1 by auto
next
case (beta x Q Qmax P Pmax)
from beta(1,7) show ?case
apply (rule_tac pbeta_cases_2)
apply (simp, simp)
proof -
case (goal2 Q' P')
with beta have "P' ≫ Pmax" "Q' ≫ Qmax" by simp+
thus ?case unfolding goal2 apply (rule_tac Lem2_5_1) by simp+
next
case (goal1 P' Q')
with beta have ih: "P' ≫ Pmax" "Q' ≫ Qmax" by simp+
show ?case unfolding goal1
apply (rule_tac pbeta.beta) using goal1 beta ih
by simp_all
qed
next
case (app al ald ar ard)
from app(7,1,2) show ?case
apply (cases "App al ar" b rule:pbeta.cases)
using app apply auto[1]
apply simp
by simp
next
case (abs al ald x) thus ?case using pbeta_lam_case_ex by blast
next
case (Y M M' σ)
from Y(3) show ?case
apply (cases rule:pbeta.cases)
proof goal_cases
case (1 M'' N'')
from 1(2) have 2: "M'' = Y σ" by (cases rule:pbeta.cases, simp)
show ?case unfolding 1 2
apply (rule pbeta.Y)
using 1 Y by simp
next
case (2 M'') show ?case unfolding 2
apply (rule pbeta.app)
using Y 2 apply simp
apply (rule pbeta.app)
apply (rule pbeta.reflY)
using Y 2 by simp
qed
qed
subsection {* Proof of $\dip(\gg)$ *}
lemma Lem2_5_2:
assumes "a ≫ b"
and "a ≫ c"
shows "∃d. b ≫ d ∧ c ≫ d"
proof -
obtain d where 1: "a >>> d" using pbeta_max_ex by auto
have "b ≫ d ∧ c ≫ d"
apply rule
apply (rule_tac pbeta_max_closes_pbeta)
using 1 assms apply simp+
apply (rule_tac pbeta_max_closes_pbeta)
using 1 assms apply simp+
done
thus ?thesis by auto
qed
subsection {* Reflexive-transitive closure of $\beta Y$ *}
inductive close :: "(trm ⇒ trm ⇒ bool) ⇒ trm ⇒ trm ⇒ bool" ("_* _ _" [80,80] 80) for R::"trm ⇒ trm ⇒ bool"
where
base[intro]: "R a b ⟹ R* a b"
| refl[intro]: "R* a a"
| trans[intro]: "⟦ R* a b ; R* b c ⟧ ⟹ R* a c"
subsection {* Proof of $\dip(\red^*)$ *}
definition DP :: "(trm ⇒ trm ⇒ bool) ⇒ (trm ⇒ trm ⇒ bool) ⇒ bool" where
"DP R T = (∀a b c. R a b ∧ T a c ⟶ (∃d. T b d ∧ R c d))"
lemma DP_R_R_imp_DP_R_Rc_pbeta:
assumes "DP pbeta pbeta"
shows "DP pbeta (close pbeta)"
using assms unfolding DP_def
apply auto
proof -
case goal1
from goal1(3,2) show ?case
apply (induct arbitrary: b rule:close.induct)
using goal1(1) by blast+
qed
lemma DP_R_R_imp_DP_Rc_Rc_pbeta:
assumes "DP pbeta pbeta"
shows "DP (close pbeta) (close pbeta)"
using assms unfolding DP_def
apply auto
proof -
case goal1
from goal1(2,3) show ?case
apply (induct arbitrary: c rule:close.induct)
using DP_R_R_imp_DP_R_Rc_pbeta using DP_def assms apply fastforce
apply auto
by blast
qed
lemma pbeta_refl[intro]: "s ≫ s"
apply (induct s rule:trm.induct)
by auto
lemma M1': "M ⇒ M' ⟹ M ≫ M'"
apply (induct M M' rule:beta_Y.induct)
by auto
lemma M1: "beta_Y* M M' ⟹ pbeta* M M'"
apply (induct M M' rule:close.induct)
apply auto
apply (rule base)
by (simp add: M1')
lemma red_r_close: "beta_Y* N N' ⟹ beta_Y* (App M N) (App M N')"
apply (induct rule:close.induct)
by auto
lemma red_l_close: "beta_Y* M M' ⟹ beta_Y* (App M N) (App M' N)"
apply (induct rule:close.induct)
by auto
lemma abs_close: "beta_Y* M M' ⟹ beta_Y* (Lam [x]. M) (Lam [x]. M')"
apply (induct rule:close.induct)
by auto
lemma M2: "pbeta* M M' ⟹ beta_Y* M M'"
proof (induct M M' rule:close.induct)
case refl show ?case by (rule close.refl)
next
case trans
show ?case apply (rule close.trans)
using trans by simp+
next
case base thus ?case
proof (induct rule:pbeta.induct)
case refl show ?case by (rule close.refl)
next
case reflY show ?case by (rule close.refl)
case (app M M' N N')
show ?case
apply (rule_tac b="App M N'" in close.trans)
using red_r_close app.hyps(4) apply auto[1]
using red_l_close app.hyps(2) by auto[1]
next
case (abs M M' x)
show ?case
using abs abs_close by simp
next
case (beta x N N' M M')
show ?case
apply (rule_tac b="App (Lam [x]. M') N" in close.trans)
apply (rule red_l_close)
apply (rule abs_close)
using beta apply simp
apply (rule_tac b="App (Lam [x]. M') N'" in close.trans)
apply (rule red_r_close)
using beta apply simp
apply (rule close.base)
apply (rule beta_Y.beta)
using beta by simp
next
case (Y M M' σ)
show ?case
apply (rule_tac b="App M (App (Y σ) M)" in close.trans)
apply (rule close.base)
apply (rule beta_Y.Y)
apply (rule_tac b="App M' (App (Y σ) M)" in close.trans)
apply (rule red_l_close)
using Y apply simp
apply (rule red_r_close)
apply (rule red_r_close)
using Y by simp
qed
qed
subsection {* Simple-typing relation $\vdash$ *}
inductive wf_ctxt :: "(name × type) list ⇒ bool"
where
nil: "wf_ctxt []"
| cons: "⟦ wf_ctxt Γ ; atom x ♯ Γ ⟧ ⟹ wf_ctxt ((x,σ)#Γ)"
equivariance wf_ctxt
inductive
wt_terms :: "(name × type) list ⇒ trm ⇒ type ⇒ bool" ("_ ⊢ _ : _")
where
var: "⟦ (x,σ) ∈ set Γ ; wf_ctxt Γ ⟧ ⟹ Γ ⊢ Var x : σ"
| app: "⟦ Γ ⊢ M : σ → τ ; Γ ⊢ N : σ ⟧ ⟹ Γ ⊢ App M N : τ"
| abs: "⟦ atom x ♯ Γ ; ((x,σ)#Γ) ⊢ M : τ ⟧ ⟹ Γ ⊢ Lam [x]. M : σ → τ"
| Y: "⟦ wf_ctxt Γ ⟧ ⟹ Γ ⊢ Y σ : (σ → σ) → σ"
equivariance wt_terms
nominal_inductive wt_terms
avoids abs: "x"
by (simp_all add: fresh_star_def fresh_Pair fresh_fact fresh_type)
subsection {* Subject reduction theorem for $\red$ *}
lemma wf_ctxt_cons: "wf_ctxt ((x, σ)#Γ) ⟹ wf_ctxt Γ ∧ atom x ♯ Γ"
apply (cases rule:wf_ctxt.cases)
by auto
lemma wt_terms_impl_wf_ctxt: "Γ ⊢ M : σ ⟹ wf_ctxt Γ"
apply (induct rule:wt_terms.induct)
by (auto simp add: wf_ctxt_cons)
lemma weakening:
fixes Γ Γ' M σ
assumes "Γ ⊢ M : σ" and "set Γ ⊆ set Γ'"
and "wf_ctxt Γ'"
shows "Γ' ⊢ M : σ"
using assms proof (nominal_induct Γ M σ avoiding: Γ' rule:wt_terms.strong_induct)
case var
show ?case
apply (rule wt_terms.var)
using var by auto
next
case app
show ?case
apply (rule wt_terms.app)
using app by auto
next
case (abs x Γ σ M τ)
have 1: "wf_ctxt ((x, σ) # Γ')"
apply (rule cons)
using abs by simp+
show ?case
apply (rule wt_terms.abs)
using "1" wf_ctxt.cases apply auto[1]
apply (rule abs(4))
using abs apply auto[1]
using 1 by simp
next
case Y thus ?case using wt_terms.Y by simp
qed
lemma wf_ctxt_exchange: "wf_ctxt ((x,σ) # (y,π) # Γ) ⟹ wf_ctxt ((y,π) # (x,σ) # Γ)"
proof goal_cases
case 1
then have 1: "wf_ctxt ((y,π) # Γ)" "atom x ♯ ((y,π) # Γ)" by (simp add: wf_ctxt_cons)+
from 1(1) have 2: "wf_ctxt Γ" "atom y ♯ Γ" by (simp add: wf_ctxt_cons)+
from 1(2) have 3: "atom x ♯ Γ" using fresh_Cons by blast
from 1(2) 2(2) have 4: "atom y ♯ ((x,σ) # Γ)" by (metis fresh_Cons fresh_Pair fresh_at_base(2) fresh_type)
show ?case
apply (rule cons)
apply (rule cons)
by (simp add: 2 3 4)+
qed
lemma exchange: "(x,σ) # (y,π) # Γ ⊢ M : δ ⟹ (y,π) # (x,σ) # Γ ⊢ M : δ"
proof goal_cases
case 1
have "set ((x,σ) # (y,π) # Γ) ⊆ set ((y,π) # (x,σ) # Γ)" by auto
thus ?case using 1 weakening wt_terms_impl_wf_ctxt wf_ctxt_exchange by blast
qed
lemma wt_terms_cases_2:
shows "Γ ⊢ Lam [x]. M : a3 ⟹ atom x ♯ Γ⟹ (⋀σ τ. a3 = σ → τ ⟹ ((x, σ)#Γ) ⊢ M : τ ⟹ P) ⟹ P"
apply atomize_elim
apply (cases Γ "Lam [x]. M" a3 rule:wt_terms.cases, simp)
proof goal_cases
case (1 x' σ M' τ)
then have 2: "M = (x' ↔ x) ∙ M'"
by (metis Abs1_eq_iff'(3) Nominal2_Base.swap_self flip_commute flip_def permute_zero)
from 1 have "((x' ↔ x) ∙ ((x', σ) # Γ)) ⊢ (x' ↔ x) ∙ M' : (x' ↔ x) ∙ τ"
by (rule_tac wt_terms.eqvt)
with 2 fresh_type have 3: "((x' ↔ x) ∙ ((x', σ) # Γ)) ⊢ M : τ" by (simp add: flip_fresh_fresh)
have "(x' ↔ x) ∙ (x', σ) = (x, σ)" using fresh_type by (simp add: flip_fresh_fresh)
then have "(x' ↔ x) ∙ ((x', σ) # Γ) = (x, σ) # ((x' ↔ x) ∙ Γ)" by simp
with 3 have 4: "(x, σ) # ((x' ↔ x) ∙ Γ) ⊢ M : τ" by simp
with 4 1 have "(x, σ) # Γ ⊢ M : τ" by (simp add: flip_fresh_fresh)
with 1 show ?case by simp
qed
lemma subst_typ_aux: "(x, τ) # Γ ⊢ Var y : σ ⟹ x = y ⟹ τ = σ"
proof (rule ccontr, goal_cases)
case 1
then have "wf_ctxt ((y, τ) # Γ)" by (simp add: wt_terms_impl_wf_ctxt)
then have "atom y ♯ Γ" by (simp add: wf_ctxt_cons)
then have "(y, σ) ∉ set Γ" by (metis (mono_tags, lifting) fresh_Cons fresh_PairD(1) fresh_append fresh_at_base(2) split_list)
with 1(3) have 2: "(y, σ) ∉ set ((y, τ) # Γ)" by simp
from 1(1) have "(y, σ) ∈ set ((y, τ) # Γ)" apply (cases rule:wt_terms.cases) by auto
with 2 show ?case by simp
qed
lemma subst_typ:
assumes "((x,τ)#Γ) ⊢ M : σ" and "Γ ⊢ N : τ"
shows "Γ ⊢ M[x ::= N] : σ"
using assms proof (nominal_induct M avoiding: Γ x N arbitrary: σ rule: trm.strong_induct)
case (Var y)
show ?case
proof (cases "x = y")
case True
show ?thesis
apply (simp add: True)
using Var subst_typ_aux True by blast
next
case False
from Var have 1: "wf_ctxt Γ" using wt_terms_impl_wf_ctxt wf_ctxt_cons by auto
from Var have "(y,σ) ∈ set ((x, τ) # Γ)" apply (cases rule:wt_terms.cases) by auto
with False have 2: "(y,σ) ∈ set Γ" by simp
show ?thesis
apply (simp add: False)
using Var
apply (rule_tac wt_terms.var)
using 1 2 by simp+
qed
next
case (App M' N')
from App(3) obtain π where "(x, τ) # Γ ⊢ M' : π → σ" "(x, τ) # Γ ⊢ N' : π"
by (cases rule:wt_terms.cases, simp)
with App(1,2,4) have ih: "Γ ⊢ M'[x ::= N] : π → σ" "Γ ⊢ N'[x ::= N] : π" by simp+
show ?case
unfolding subst.simps
apply (rule wt_terms.app)
using ih by simp+
next
case (Lam x' M)
from Lam(5) obtain π δ where 1: "σ = π → δ" "(x, τ) # Γ ⊢ Lam [x']. M : π → δ" by (cases rule:wt_terms.cases, simp)
from 1(2) have "(x', π) # (x, τ) # Γ ⊢ M : δ" apply (rule wt_terms_cases_2)
using Lam(1,2) apply (simp add: fresh_Cons fresh_Pair fresh_type)
by simp
then have "(x, τ) # (x', π) # Γ ⊢ M : δ" by (rule exchange)
with Lam(4,6) have ih: "(x', π) # Γ ⊢ M [x ::= N] : δ"
by (meson Lam.hyps(1) cons set_subset_Cons weakening wt_terms_impl_wf_ctxt)
show ?case apply (subst subst.simps)
using Lam apply simp
unfolding 1(1)
apply (rule wt_terms.abs)
using Lam apply simp
using ih by simp
next
case (Y γ)
from Y(1) have 1: "σ = (γ → γ) → γ" by (cases rule:wt_terms.cases, simp)
show ?case unfolding subst.simps 1
apply (rule wt_terms.Y)
using Y wt_terms_impl_wf_ctxt wf_ctxt_cons by simp
qed
lemma beta_Y_typ:
assumes "Γ ⊢ M : σ"
and "M ⇒ M'"
shows "Γ ⊢ M' : σ"
using assms(2,1)
proof (nominal_induct M M' avoiding: Γ arbitrary: σ rule: beta_Y.strong_induct)
case (red_L M M' N)
from red_L(3) obtain τ where 1: "Γ ⊢ M : τ → σ" "Γ ⊢ N : τ"
apply (cases rule:wt_terms.cases) by simp
with red_L(2) have "Γ ⊢ M' : τ → σ" by simp
thus ?case
apply (rule wt_terms.app)
using 1 by simp
next
case (red_R N N' M)
from red_R(3) obtain τ where 1: "Γ ⊢ M : τ → σ" "Γ ⊢ N : τ"
apply (cases rule:wt_terms.cases) by simp
with red_R(2) have 2: "Γ ⊢ N' : τ" by simp
show ?case
apply (rule wt_terms.app)
using 1 2 by simp+
next
case (abs M M' x)
from abs(4) obtain π τ where 1: "σ = π → τ" "Γ ⊢ Lam [x]. M : π → τ"
apply (cases rule:wt_terms.cases) using abs.prems by blast
from 1(2) abs(1) have 2: "((x,π)#Γ) ⊢ M : τ" by (rule wt_terms_cases_2, simp)
with abs(3) have 3: "((x,π)#Γ) ⊢ M' : τ" by simp
show ?case
apply (subst 1(1))
apply (rule wt_terms.abs)
using abs 2 3 by simp+
next
case (beta x N M)
from beta(3) obtain τ where 1: "Γ ⊢ Lam [x]. M : τ → σ" "Γ ⊢ N : τ"
apply (cases rule:wt_terms.cases) by simp
from 1(1) beta(1) have 2: "((x,τ)#Γ) ⊢ M : σ" by (rule wt_terms_cases_2, simp)
show ?case
apply (rule subst_typ)
using 2 1(2) by simp+
next
case (Y τ M)
from Y obtain π where 1: "Γ ⊢ (Y τ) : π → σ" "Γ ⊢ M : π"
apply (cases rule:wt_terms.cases) by simp
have "Γ ⊢ (Y τ) : (τ → τ) → τ" apply (rule wt_terms.Y)
using wt_terms_impl_wf_ctxt Y by simp
with 1(1) have "π → σ = (τ → τ) → τ" apply (cases rule:wt_terms.cases) by simp
then have 2: "π = τ → τ" "σ = τ" by simp+
show ?case
apply (subst 2)
apply (rule wt_terms.app)
defer
apply (rule wt_terms.app)
apply (rule wt_terms.Y)
using wt_terms_impl_wf_ctxt Y apply simp
using 1(2) 2(1) by simp+
qed
lemma beta_Y_c_typ:
assumes "Γ ⊢ M : σ"
and "beta_Y* M M'"
shows "Γ ⊢ M' : σ"
using assms(2,1)
apply (induct M M' arbitrary: σ rule: close.induct)
using beta_Y_typ by auto
subsection {* Church Rosser Theorem *}
lemma church_rosser_typ:
assumes "Γ ⊢ a : σ"
and "beta_Y* a b"
and "beta_Y* a c"
shows "∃d. beta_Y* b d ∧ beta_Y* c d ∧ Γ ⊢ d : σ"
proof -
from assms have "pbeta* a b" "pbeta* a c" using M1 base by simp+
then obtain d where "pbeta* b d" "pbeta* c d" by (metis DP_R_R_imp_DP_Rc_Rc_pbeta DP_def Lem2_5_2)
thus ?thesis using M2 beta_Y_c_typ assms by blast
qed
end