generate "case_cong" property
authorblanchet
Thu, 30 Aug 2012 16:50:03 +0200
changeset 49032 c2a7bedd57d8
parent 49031 632ee0da3c5b
child 49033 23ef2d429931
generate "case_cong" property
src/HOL/Codatatype/Tools/bnf_sugar.ML
src/HOL/Codatatype/Tools/bnf_sugar_tactics.ML
--- a/src/HOL/Codatatype/Tools/bnf_sugar.ML	Thu Aug 30 15:57:14 2012 +0200
+++ b/src/HOL/Codatatype/Tools/bnf_sugar.ML	Thu Aug 30 16:50:03 2012 +0200
@@ -37,6 +37,10 @@
 
 fun index_of_half_cell n j k = index_of_half_row n j + k - (j + 1);
 
+val mk_Trueprop_eq = HOLogic.mk_Trueprop o HOLogic.mk_eq;
+
+fun eta_expand_caseof_arg f xs = fold_rev Term.lambda xs (Term.list_comb (f, xs));
+
 fun prepare_sugar prep_term (((raw_ctrs, raw_caseof), disc_names), sel_namess) no_defs_lthy =
   let
     (* TODO: sanity checks on arguments *)
@@ -78,31 +82,34 @@
     val caseofB = mk_caseof As B;
     val caseofB_Ts = map (fn Ts => Ts ---> B) ctr_Tss;
 
-    val (((((xss, yss), fs), (v, v')), p), names_lthy) = no_defs_lthy |>
+    val (((((((xss, yss), fs), gs), (v, v')), w), p), names_lthy) = no_defs_lthy |>
       mk_Freess "x" ctr_Tss
       ||>> mk_Freess "y" ctr_Tss
       ||>> mk_Frees "f" caseofB_Ts
+      ||>> mk_Frees "g" caseofB_Ts
       ||>> yield_singleton (apfst (op ~~) oo mk_Frees' "v") T
+      ||>> yield_singleton (mk_Frees "w") T
       ||>> yield_singleton (mk_Frees "P") HOLogic.boolT;
 
     val xctrs = map2 (curry Term.list_comb) ctrs xss;
     val yctrs = map2 (curry Term.list_comb) ctrs yss;
-    val eta_fs = map2 (fn f => fn xs => fold_rev Term.lambda xs (Term.list_comb (f, xs))) fs xss;
+
+    val eta_fs = map2 eta_expand_caseof_arg fs xss;
+    val eta_gs = map2 eta_expand_caseof_arg gs xss;
 
     val exist_xs_v_eq_ctrs =
       map2 (fn xctr => fn xs => list_exists_free xs (HOLogic.mk_eq (v, xctr))) xctrs xss;
 
-    fun mk_caseof_args k xs x T =
+    fun mk_sel_caseof_args k xs x T =
       map2 (fn Ts => fn i => if i = k then fold_rev Term.lambda xs x else mk_undef T Ts) ctr_Tss ks;
 
     fun disc_spec b exist_xs_v_eq_ctr =
-      HOLogic.mk_Trueprop (HOLogic.mk_eq (Free (Binding.name_of b, T --> HOLogic.boolT) $ v,
-        exist_xs_v_eq_ctr));
+      mk_Trueprop_eq (Free (Binding.name_of b, T --> HOLogic.boolT) $ v, exist_xs_v_eq_ctr);
 
     fun sel_spec b x xs k =
       let val T' = fastype_of x in
-        HOLogic.mk_Trueprop (HOLogic.mk_eq (Free (Binding.name_of b, T --> T') $ v,
-            Term.list_comb (mk_caseof As T', mk_caseof_args k xs x T') $ v))
+        mk_Trueprop_eq (Free (Binding.name_of b, T --> T') $ v,
+          Term.list_comb (mk_caseof As T', mk_sel_caseof_args k xs x T') $ v)
       end;
 
     val (((raw_discs, (_, raw_disc_defs)), (raw_selss, (_, raw_sel_defss))), (lthy', lthy)) =
@@ -131,13 +138,10 @@
     val discs = map (mk_disc_or_sel As) discs0;
     val selss = map (map (mk_disc_or_sel As)) selss0;
 
-    fun mk_imp_p Q = Logic.list_implies (Q, HOLogic.mk_Trueprop p);
+    fun mk_imp_p Qs = Logic.list_implies (Qs, HOLogic.mk_Trueprop p);
 
     val goal_exhaust =
-      let
-        fun mk_prem xctr xs =
-          fold_rev Logic.all xs (mk_imp_p [HOLogic.mk_Trueprop (HOLogic.mk_eq (v, xctr))]);
-      in
+      let fun mk_prem xctr xs = fold_rev Logic.all xs (mk_imp_p [mk_Trueprop_eq (v, xctr)]) in
         mk_imp_p (map2 mk_prem xctrs xss)
       end;
 
@@ -145,9 +149,8 @@
       let
         fun mk_goal _ _ [] [] = NONE
           | mk_goal xctr yctr xs ys =
-            SOME (HOLogic.mk_Trueprop (HOLogic.mk_eq
-              (HOLogic.mk_eq (xctr, yctr),
-               Library.foldr1 HOLogic.mk_conj (map2 (curry HOLogic.mk_eq) xs ys))));
+            SOME (mk_Trueprop_eq (HOLogic.mk_eq (xctr, yctr),
+              Library.foldr1 HOLogic.mk_conj (map2 (curry HOLogic.mk_eq) xs ys)));
       in
         map_filter I (map4 mk_goal xctrs yctrs xss yss)
       end;
@@ -158,8 +161,7 @@
     val goal_cases =
       let
         val lhs0 = Term.list_comb (caseofB, eta_fs);
-        fun mk_goal xctr xs f =
-          HOLogic.mk_Trueprop (HOLogic.mk_eq (lhs0 $ xctr, Term.list_comb (f, xs)));
+        fun mk_goal xctr xs f = mk_Trueprop_eq (lhs0 $ xctr, Term.list_comb (f, xs));
       in
         map3 mk_goal xctrs xss fs
       end;
@@ -170,6 +172,12 @@
       let
         val [[exhaust_thm], inject_thms, half_distinct_thms, case_thms] = thmss;
 
+        val exhaust_thm' =
+          let val Tinst = map (pairself (certifyT lthy)) (map Logic.varifyT_global As ~~ As) in
+            Drule.instantiate' [] [SOME (certify lthy v)]
+              (Thm.instantiate (Tinst, []) (Drule.zero_var_indexes exhaust_thm))
+          end;
+
         val other_half_distinct_thms = map (fn thm => thm RS not_sym) half_distinct_thms;
 
         val nchotomy_thm =
@@ -189,7 +197,7 @@
                 val cTs =
                   map ((fn T' => certifyT lthy (if T' = B then T else T')) o TFree)
                     (rev (Term.add_tfrees goal_case []));
-                val cxs = map (certify lthy) (mk_caseof_args k xs x T);
+                val cxs = map (certify lthy) (mk_sel_caseof_args k xs x T);
               in
                 Local_Defs.fold lthy [sel_def]
                   (Drule.instantiate' (map SOME cTs) (map SOME cxs) case_thm)
@@ -255,8 +263,8 @@
           let
             fun mk_goal ctr disc sels =
               Logic.all v (Logic.mk_implies (HOLogic.mk_Trueprop (disc $ v),
-                HOLogic.mk_Trueprop (HOLogic.mk_eq ((null sels ? swap)
-                  (Term.list_comb (ctr, map (fn sel => sel $ v) sels), v)))));
+                mk_Trueprop_eq ((null sels ? swap)
+                  (Term.list_comb (ctr, map (fn sel => sel $ v) sels), v))));
             val goals = map3 mk_goal ctrs discs selss;
           in
             map4 (fn goal => fn m => fn discD => fn sel_thms =>
@@ -275,19 +283,28 @@
 
             val lhs = Term.list_comb (caseofB, eta_fs) $ v;
             val rhs = mk_rhs discs fs selss;
-            val goal = HOLogic.mk_Trueprop (HOLogic.mk_eq (lhs, rhs));
-
-            val Tinst = map (pairself (certifyT lthy)) (map Logic.varifyT_global As ~~ As);
-            val exhaust_thm' =
-              Drule.instantiate' [] [SOME (certify lthy v)]
-                (Thm.instantiate (Tinst, []) (Drule.zero_var_indexes exhaust_thm));
+            val goal = mk_Trueprop_eq (lhs, rhs);
           in
             Skip_Proof.prove lthy [] [] goal (fn {context = ctxt, ...} =>
               mk_case_disc_tac ctxt exhaust_thm' case_thms disc_thms sel_thmss)
             |> singleton (Proof_Context.export names_lthy lthy)
           end;
 
-        val case_cong_thm = TrueI;
+        val case_cong_thm =
+          let
+            fun mk_prem xctr xs f g =
+              fold_rev Logic.all xs (Logic.mk_implies (mk_Trueprop_eq (v, xctr),
+                mk_Trueprop_eq (f, g)));
+            fun mk_caseof_term fs v = Term.list_comb (caseofB, fs) $ v;
+
+            val goal =
+              Logic.list_implies (mk_Trueprop_eq (v, w) :: map4 mk_prem xctrs xss fs gs,
+                 mk_Trueprop_eq (mk_caseof_term eta_fs v, mk_caseof_term eta_gs w));
+          in
+            Skip_Proof.prove lthy [] [] goal (fn {context = ctxt, ...} =>
+              mk_case_cong_tac ctxt exhaust_thm' case_thms)
+            |> singleton (Proof_Context.export names_lthy lthy)
+          end;
 
         val weak_case_cong_thms = TrueI;
 
--- a/src/HOL/Codatatype/Tools/bnf_sugar_tactics.ML	Thu Aug 30 15:57:14 2012 +0200
+++ b/src/HOL/Codatatype/Tools/bnf_sugar_tactics.ML	Thu Aug 30 16:50:03 2012 +0200
@@ -7,6 +7,7 @@
 
 signature BNF_SUGAR_TACTICS =
 sig
+  val mk_case_cong_tac: Proof.context -> thm -> thm list -> tactic
   val mk_case_disc_tac: Proof.context -> thm -> thm list -> thm list -> thm list list -> tactic
   val mk_ctr_sel_tac: Proof.context -> int -> thm -> thm list -> tactic
   val mk_disc_exhaust_tac: int -> thm -> thm list -> tactic
@@ -25,6 +26,8 @@
   thm RS @{thm eq_False[THEN iffD2]}
   handle THM _ => thm RS @{thm eq_True[THEN iffD2]}
 
+fun context_ss_only thms = map_simpset (fn ss => Simplifier.clear_ss ss addsimps thms)
+
 fun mk_nchotomy_tac n exhaust =
   (rtac allI THEN' rtac exhaust THEN'
    EVERY' (maps (fn k => [rtac (mk_disjIN n k), REPEAT_DETERM o rtac exI, atac]) (1 upto n))) 1;
@@ -53,13 +56,16 @@
       SELECT_GOAL (Local_Defs.unfold_tac ctxt sel_thms) THEN'
       rtac refl)) 1;
 
-fun mk_case_disc_tac ctxt exhaust case_thms disc_thms sel_thmss =
+fun mk_case_disc_tac ctxt exhaust' case_thms disc_thms sel_thmss =
   let val base_unfolds = @{thms if_True if_False} @ map eq_True_or_False disc_thms in
-    (rtac exhaust THEN'
+    (rtac exhaust' THEN'
      EVERY' (map2 (fn case_thm => fn sel_thms => EVERY' [
        hyp_subst_tac THEN'
        SELECT_GOAL (Local_Defs.unfold_tac ctxt (base_unfolds @ sel_thms)) THEN'
        rtac case_thm]) case_thms sel_thmss)) 1
   end;
 
+fun mk_case_cong_tac ctxt exhaust' case_thms =
+  rtac exhaust' 1 THEN ALLGOALS (clarsimp_tac (context_ss_only case_thms ctxt));
+
 end;