src/HOL/BNF/Tools/ctr_sugar_tactics.ML
author blanchet
Tue, 01 Oct 2013 14:05:25 +0200
changeset 55145 b15cfc2864de
parent 55144 07028b08045f
permissions -rw-r--r--
refactoring -- splitting between constructor sugar dependencies and true BNF dependencies
     1 (*  Title:      HOL/BNF/Tools/ctr_sugar_tactics.ML
     2     Author:     Jasmin Blanchette, TU Muenchen
     3     Copyright   2012
     4 
     5 Tactics for wrapping existing freely generated type's constructors.
     6 *)
     7 
     8 signature CTR_SUGAR_GENERAL_TACTICS =
     9 sig
    10   val select_prem_tac: int -> (int -> tactic) -> int -> int -> tactic
    11   val unfold_thms_tac: Proof.context -> thm list -> tactic
    12 end;
    13 
    14 signature CTR_SUGAR_TACTICS =
    15 sig
    16   include CTR_SUGAR_GENERAL_TACTICS
    17 
    18   val mk_alternate_disc_def_tac: Proof.context -> int -> thm -> thm -> thm -> tactic
    19   val mk_case_tac: Proof.context -> int -> int -> thm -> thm list -> thm list list -> tactic
    20   val mk_case_cong_tac: Proof.context -> thm -> thm list -> tactic
    21   val mk_case_conv_if_tac: Proof.context -> int -> thm -> thm list -> thm list list ->
    22     thm list list -> tactic
    23   val mk_collapse_tac: Proof.context -> int -> thm -> thm list -> tactic
    24   val mk_disc_exhaust_tac: int -> thm -> thm list -> tactic
    25   val mk_expand_tac: Proof.context -> int -> int list -> thm -> thm -> thm list ->
    26     thm list list list -> thm list list list -> tactic
    27   val mk_half_disc_exclude_tac: Proof.context -> int -> thm -> thm -> tactic
    28   val mk_nchotomy_tac: int -> thm -> tactic
    29   val mk_other_half_disc_exclude_tac: thm -> tactic
    30   val mk_sel_exhaust_tac: int -> thm -> thm list -> tactic
    31   val mk_split_tac: Proof.context -> thm -> thm list -> thm list list -> thm list list -> thm list
    32     list list -> tactic
    33   val mk_split_asm_tac: Proof.context -> thm -> tactic
    34   val mk_unique_disc_def_tac: int -> thm -> tactic
    35 end;
    36 
    37 structure Ctr_Sugar_Tactics : CTR_SUGAR_TACTICS =
    38 struct
    39 
    40 open Ctr_Sugar_Util
    41 
    42 val meta_mp = @{thm meta_mp};
    43 
    44 fun select_prem_tac n tac k = DETERM o (EVERY' [REPEAT_DETERM_N (k - 1) o etac thin_rl,
    45   tac, REPEAT_DETERM_N (n - k) o etac thin_rl]);
    46 
    47 fun unfold_thms_tac _ [] = all_tac
    48   | unfold_thms_tac ctxt thms = Local_Defs.unfold_tac ctxt (distinct Thm.eq_thm_prop thms);
    49 
    50 fun if_P_or_not_P_OF pos thm = thm RS (if pos then @{thm if_P} else @{thm if_not_P});
    51 
    52 fun mk_nchotomy_tac n exhaust =
    53   HEADGOAL (rtac allI THEN' rtac exhaust THEN'
    54    EVERY' (maps (fn k => [rtac (mk_disjIN n k), REPEAT_DETERM o rtac exI, atac]) (1 upto n)));
    55 
    56 fun mk_unique_disc_def_tac m uexhaust =
    57   HEADGOAL (EVERY' [rtac iffI, rtac uexhaust, REPEAT_DETERM_N m o rtac exI, atac, rtac refl]);
    58 
    59 fun mk_alternate_disc_def_tac ctxt k other_disc_def distinct uexhaust =
    60   HEADGOAL (EVERY' ([rtac (other_disc_def RS @{thm arg_cong[of _ _ Not]} RS trans),
    61     rtac @{thm iffI_np}, REPEAT_DETERM o etac exE,
    62     hyp_subst_tac ctxt, SELECT_GOAL (unfold_thms_tac ctxt [not_ex]), REPEAT_DETERM o rtac allI,
    63     rtac distinct, rtac uexhaust] @
    64     (([etac notE, REPEAT_DETERM o rtac exI, atac], [REPEAT_DETERM o rtac exI, atac])
    65      |> k = 1 ? swap |> op @)));
    66 
    67 fun mk_half_disc_exclude_tac ctxt m discD disc' =
    68   HEADGOAL (dtac discD THEN' REPEAT_DETERM_N m o etac exE THEN' hyp_subst_tac ctxt THEN'
    69     rtac disc');
    70 
    71 fun mk_other_half_disc_exclude_tac half = HEADGOAL (etac @{thm contrapos_pn} THEN' etac half);
    72 
    73 fun mk_disc_or_sel_exhaust_tac n exhaust destIs =
    74   HEADGOAL (rtac exhaust THEN'
    75     EVERY' (map2 (fn k => fn destI => dtac destI THEN'
    76       select_prem_tac n (etac meta_mp) k THEN' atac) (1 upto n) destIs));
    77 
    78 val mk_disc_exhaust_tac = mk_disc_or_sel_exhaust_tac;
    79 
    80 fun mk_sel_exhaust_tac n disc_exhaust collapses =
    81   mk_disc_or_sel_exhaust_tac n disc_exhaust collapses ORELSE
    82   HEADGOAL (etac meta_mp THEN' resolve_tac collapses);
    83 
    84 fun mk_collapse_tac ctxt m discD sels =
    85   HEADGOAL (dtac discD THEN'
    86     (if m = 0 then
    87        atac
    88      else
    89        REPEAT_DETERM_N m o etac exE THEN' hyp_subst_tac ctxt THEN'
    90        SELECT_GOAL (unfold_thms_tac ctxt sels) THEN' rtac refl));
    91 
    92 fun mk_expand_tac ctxt n ms udisc_exhaust vdisc_exhaust uncollapses disc_excludesss
    93     disc_excludesss' =
    94   if ms = [0] then
    95     HEADGOAL (rtac (@{thm trans_sym} OF (replicate 2 (the_single uncollapses))) THEN'
    96       TRY o EVERY' [rtac udisc_exhaust, atac, rtac vdisc_exhaust, atac])
    97   else
    98     let val ks = 1 upto n in
    99       HEADGOAL (rtac udisc_exhaust THEN'
   100         EVERY' (map5 (fn k => fn m => fn disc_excludess => fn disc_excludess' =>
   101             fn uuncollapse =>
   102           EVERY' [rtac (uuncollapse RS trans) THEN' TRY o atac,
   103             rtac sym, rtac vdisc_exhaust,
   104             EVERY' (map4 (fn k' => fn disc_excludes => fn disc_excludes' => fn vuncollapse =>
   105               EVERY'
   106                 (if k' = k then
   107                    [rtac (vuncollapse RS trans), TRY o atac] @
   108                    (if m = 0 then
   109                       [rtac refl]
   110                     else
   111                       [if n = 1 then K all_tac else EVERY' [dtac meta_mp, atac, dtac meta_mp, atac],
   112                        REPEAT_DETERM_N (Int.max (0, m - 1)) o etac conjE,
   113                        asm_simp_tac (ss_only [] ctxt)])
   114                  else
   115                    [dtac (the_single (if k = n then disc_excludes else disc_excludes')),
   116                     etac (if k = n then @{thm iff_contradict(1)} else @{thm iff_contradict(2)}),
   117                     atac, atac]))
   118               ks disc_excludess disc_excludess' uncollapses)])
   119           ks ms disc_excludesss disc_excludesss' uncollapses))
   120     end;
   121 
   122 fun mk_case_same_ctr_tac ctxt injects =
   123   REPEAT_DETERM o etac exE THEN' etac conjE THEN'
   124     (case injects of
   125       [] => atac
   126     | [inject] => dtac (inject RS iffD1) THEN' REPEAT_DETERM o etac conjE THEN'
   127         hyp_subst_tac ctxt THEN' rtac refl);
   128 
   129 fun mk_case_distinct_ctrs_tac ctxt distincts =
   130   REPEAT_DETERM o etac exE THEN' etac conjE THEN' full_simp_tac (ss_only distincts ctxt);
   131 
   132 fun mk_case_tac ctxt n k case_def injects distinctss =
   133   let
   134     val case_def' = mk_unabs_def (n + 1) (case_def RS meta_eq_to_obj_eq);
   135     val ks = 1 upto n;
   136   in
   137     HEADGOAL (rtac (case_def' RS trans) THEN' rtac @{thm the_equality} THEN'
   138       rtac (mk_disjIN n k) THEN' REPEAT_DETERM o rtac exI THEN' rtac conjI THEN' rtac refl THEN'
   139       rtac refl THEN'
   140       EVERY' (map2 (fn k' => fn distincts =>
   141         (if k' < n then etac disjE else K all_tac) THEN'
   142         (if k' = k then mk_case_same_ctr_tac ctxt injects
   143          else mk_case_distinct_ctrs_tac ctxt distincts)) ks distinctss))
   144   end;
   145 
   146 fun mk_case_conv_if_tac ctxt n uexhaust cases discss' selss =
   147   HEADGOAL (rtac uexhaust THEN'
   148     EVERY' (map3 (fn casex => fn if_discs => fn sels =>
   149         EVERY' [hyp_subst_tac ctxt, SELECT_GOAL (unfold_thms_tac ctxt (if_discs @ sels)),
   150           rtac casex])
   151       cases (map2 (seq_conds if_P_or_not_P_OF n) (1 upto n) discss') selss));
   152 
   153 fun mk_case_cong_tac ctxt uexhaust cases =
   154   HEADGOAL (rtac uexhaust THEN'
   155     EVERY' (maps (fn casex => [dtac sym, asm_simp_tac (ss_only [casex] ctxt)]) cases));
   156 
   157 fun mk_split_tac ctxt uexhaust cases selss injectss distinctsss =
   158   HEADGOAL (rtac uexhaust) THEN
   159   ALLGOALS (fn k => (hyp_subst_tac ctxt THEN'
   160      simp_tac (ss_only (@{thms simp_thms} @ cases @ nth selss (k - 1) @ nth injectss (k - 1) @
   161        flat (nth distinctsss (k - 1))) ctxt)) k) THEN
   162   ALLGOALS (blast_tac (put_claset (claset_of @{theory_context HOL}) ctxt));
   163 
   164 val split_asm_thms = @{thms imp_conv_disj de_Morgan_conj de_Morgan_disj not_not not_ex};
   165 
   166 fun mk_split_asm_tac ctxt split =
   167   HEADGOAL (rtac (split RS trans)) THEN unfold_thms_tac ctxt split_asm_thms THEN
   168   HEADGOAL (rtac refl);
   169 
   170 end;
   171 
   172 structure Ctr_Sugar_General_Tactics: CTR_SUGAR_GENERAL_TACTICS = Ctr_Sugar_Tactics;