src/HOL/Nominal/Examples/LocalWeakening.thy
author krauss
Thu, 28 Aug 2008 17:54:18 +0200
changeset 28042 1471f2974eb1
parent 26966 071f40487734
child 29097 68245155eb58
permissions -rw-r--r--
more function -> fun
     1 (* $Id$ *)
     2 
     3 (* Formalisation of weakening using locally nameless    *)
     4 (* terms; the nominal infrastructure can also derive    *)
     5 (* strong induction principles for such representations *)
     6 (*                                                      *)
     7 (* Authors: Christian Urban and Randy Pollack           *)
     8 theory LocalWeakening
     9   imports "../Nominal"
    10 begin
    11 
    12 atom_decl name
    13 
    14 text {* 
    15   Curry-style lambda terms in locally nameless 
    16   representation without any binders           
    17 *}
    18 nominal_datatype llam = 
    19     lPar "name"
    20   | lVar "nat"
    21   | lApp "llam" "llam"
    22   | lLam "llam"
    23 
    24 text {* definition of vsub - at the moment a bit cumbersome *}
    25 
    26 lemma llam_cases:
    27   "(\<exists>a. t = lPar a) \<or> (\<exists>n. t = lVar n) \<or> (\<exists>t1 t2. t = lApp t1 t2) \<or> 
    28    (\<exists>t1. t = lLam t1)"
    29 by (induct t rule: llam.induct)
    30    (auto simp add: llam.inject)
    31 
    32 consts llam_size :: "llam \<Rightarrow> nat"
    33 
    34 nominal_primrec
    35  "llam_size (lPar a) = 1"
    36  "llam_size (lVar n) = 1"
    37  "llam_size (lApp t1 t2) = 1 + (llam_size t1) + (llam_size t2)"
    38  "llam_size (lLam t) = 1 + (llam_size t)"
    39 by (rule TrueI)+
    40 
    41 function  
    42   vsub :: "llam \<Rightarrow> nat \<Rightarrow> llam \<Rightarrow> llam"
    43 where
    44    vsub_lPar: "vsub (lPar p) x s = lPar p"
    45  | vsub_lVar: "vsub (lVar n) x s = (if n < x then (lVar n)
    46                       else (if n = x then s else (lVar (n - 1))))"
    47  | vsub_lApp: "vsub (lApp t u) x s = (lApp (vsub t x s) (vsub u x s))"
    48  | vsub_lLam: "vsub (lLam t) x s = (lLam (vsub t (x + 1) s))"
    49 using llam_cases
    50 apply(auto simp add: llam.inject)
    51 apply(rotate_tac 4)
    52 apply(drule_tac x="a" in meta_spec)
    53 apply(blast)
    54 done
    55 termination by (relation "measure (llam_size \<circ> fst)") auto
    56 
    57 lemma vsub_eqvt[eqvt]:
    58   fixes pi::"name prm" 
    59   shows "pi\<bullet>(vsub t n s) = vsub (pi\<bullet>t) (pi\<bullet>n) (pi\<bullet>s)"
    60 by (induct t arbitrary: n rule: llam.induct)
    61    (simp_all add: perm_nat_def)
    62 
    63 constdefs
    64   freshen :: "llam \<Rightarrow> name \<Rightarrow> llam"
    65   "freshen t p \<equiv> vsub t 0 (lPar p)"
    66 
    67 lemma freshen_eqvt[eqvt]:
    68   fixes pi::"name prm" 
    69   shows "pi\<bullet>(freshen t p) = freshen (pi\<bullet>t) (pi\<bullet>p)"
    70 by (simp add: vsub_eqvt freshen_def perm_nat_def)
    71 
    72 text {* types *}
    73 
    74 nominal_datatype ty =
    75     TVar "nat"
    76   | TArr "ty" "ty" (infix "\<rightarrow>" 200)
    77 
    78 lemma ty_fresh[simp]:
    79   fixes x::"name"
    80   and   T::"ty"
    81   shows "x\<sharp>T"
    82 by (induct T rule: ty.induct) 
    83    (simp_all add: fresh_nat)
    84 
    85 text {* valid contexts *}
    86 
    87 types cxt = "(name\<times>ty) list"
    88 
    89 inductive
    90   valid :: "cxt \<Rightarrow> bool"
    91 where
    92   v1[intro]: "valid []"
    93 | v2[intro]: "\<lbrakk>valid \<Gamma>;a\<sharp>\<Gamma>\<rbrakk>\<Longrightarrow> valid ((a,T)#\<Gamma>)"
    94 
    95 equivariance valid
    96 
    97 lemma v2_elim:
    98   assumes a: "valid ((a,T)#\<Gamma>)"
    99   shows   "a\<sharp>\<Gamma> \<and> valid \<Gamma>"
   100 using a by (cases) (auto)
   101 
   102 text {* "weak" typing relation *}
   103 
   104 inductive
   105   typing :: "cxt\<Rightarrow>llam\<Rightarrow>ty\<Rightarrow>bool" (" _ \<turnstile> _ : _ " [60,60,60] 60)
   106 where
   107   t_lPar[intro]: "\<lbrakk>valid \<Gamma>; (x,T)\<in>set \<Gamma>\<rbrakk>\<Longrightarrow> \<Gamma> \<turnstile> lPar x : T"
   108 | t_lApp[intro]: "\<lbrakk>\<Gamma> \<turnstile> t1 : T1\<rightarrow>T2; \<Gamma> \<turnstile> t2 : T1\<rbrakk>\<Longrightarrow> \<Gamma> \<turnstile> lApp t1 t2 : T2"
   109 | t_lLam[intro]: "\<lbrakk>x\<sharp>t; (x,T1)#\<Gamma> \<turnstile> freshen t x : T2\<rbrakk>\<Longrightarrow> \<Gamma> \<turnstile> lLam t : T1\<rightarrow>T2"
   110 
   111 equivariance typing
   112 
   113 lemma typing_implies_valid:
   114   assumes a: "\<Gamma> \<turnstile> t : T"
   115   shows "valid \<Gamma>"
   116 using a by (induct) (auto dest: v2_elim)
   117 
   118 text {* 
   119   we have to explicitly state that nominal_inductive should strengthen 
   120   over the variable x (since x is not a binder)
   121 *}
   122 nominal_inductive typing
   123   avoids t_lLam: x
   124   by (auto simp add: fresh_prod dest: v2_elim typing_implies_valid)
   125   
   126 text {* strong induction principle for typing *}
   127 thm typing.strong_induct
   128 
   129 text {* sub-contexts *}
   130 
   131 abbreviation
   132   "sub_context" :: "cxt \<Rightarrow> cxt \<Rightarrow> bool" ("_ \<subseteq> _" [60,60] 60) 
   133 where
   134   "\<Gamma>1 \<subseteq> \<Gamma>2 \<equiv> \<forall>x T. (x,T)\<in>set \<Gamma>1 \<longrightarrow> (x,T)\<in>set \<Gamma>2"
   135 
   136 lemma weakening_almost_automatic:
   137   fixes \<Gamma>1 \<Gamma>2 :: cxt
   138   assumes a: "\<Gamma>1 \<turnstile> t : T"
   139   and     b: "\<Gamma>1 \<subseteq> \<Gamma>2"
   140   and     c: "valid \<Gamma>2"
   141 shows "\<Gamma>2 \<turnstile> t : T"
   142 using a b c
   143 apply(nominal_induct \<Gamma>1 t T avoiding: \<Gamma>2 rule: typing.strong_induct)
   144 apply(auto)
   145 apply(drule_tac x="(x,T1)#\<Gamma>2" in meta_spec)
   146 apply(auto intro!: t_lLam)
   147 done
   148 
   149 lemma weakening_in_more_detail:
   150   fixes \<Gamma>1 \<Gamma>2 :: cxt
   151   assumes a: "\<Gamma>1 \<turnstile> t : T"
   152   and     b: "\<Gamma>1 \<subseteq> \<Gamma>2"
   153   and     c: "valid \<Gamma>2"
   154 shows "\<Gamma>2 \<turnstile> t : T"
   155 using a b c
   156 proof(nominal_induct \<Gamma>1 t T avoiding: \<Gamma>2 rule: typing.strong_induct)
   157   case (t_lPar \<Gamma>1 x T \<Gamma>2)  (* variable case *)
   158   have "\<Gamma>1 \<subseteq> \<Gamma>2" by fact 
   159   moreover  
   160   have "valid \<Gamma>2" by fact 
   161   moreover 
   162   have "(x,T)\<in> set \<Gamma>1" by fact
   163   ultimately show "\<Gamma>2 \<turnstile> lPar x : T" by auto
   164 next
   165   case (t_lLam x t T1 \<Gamma>1 T2 \<Gamma>2) (* lambda case *)
   166   have vc: "x\<sharp>\<Gamma>2" "x\<sharp>t" by fact+  (* variable convention *)
   167   have ih: "\<lbrakk>(x,T1)#\<Gamma>1 \<subseteq> (x,T1)#\<Gamma>2; valid ((x,T1)#\<Gamma>2)\<rbrakk> \<Longrightarrow> (x,T1)#\<Gamma>2 \<turnstile> freshen t x : T2" by fact
   168   have "\<Gamma>1 \<subseteq> \<Gamma>2" by fact
   169   then have "(x,T1)#\<Gamma>1 \<subseteq> (x,T1)#\<Gamma>2" by simp
   170   moreover
   171   have "valid \<Gamma>2" by fact
   172   then have "valid ((x,T1)#\<Gamma>2)" using vc by (simp add: v2)
   173   ultimately have "(x,T1)#\<Gamma>2 \<turnstile> freshen t x : T2" using ih by simp
   174   with vc show "\<Gamma>2 \<turnstile> lLam t : T1\<rightarrow>T2" by auto
   175 next 
   176   case (t_lApp \<Gamma>1 t1 T1 T2 t2 \<Gamma>2)
   177   then show "\<Gamma>2 \<turnstile> lApp t1 t2 : T2" by auto
   178 qed
   179 
   180 end