| author | wenzelm | 
| Fri, 28 Apr 2017 13:21:03 +0200 | |
| changeset 65604 | 637aa8e93cd7 | 
| parent 63352 | 4eaf35781b23 | 
| child 69568 | de09a7261120 | 
| permissions | -rw-r--r-- | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 1 | (* Title: HOL/Library/simps_case_conv.ML | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 2 | Author: Lars Noschinski, TU Muenchen | 
| 53433 | 3 | Author: Gerwin Klein, NICTA | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 4 | |
| 53433 | 5 | Convert function specifications between the representation as a list | 
| 6 | of equations (with patterns on the lhs) and a single equation (with a | |
| 7 | nested case expression on the rhs). | |
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 8 | *) | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 9 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 10 | signature SIMPS_CASE_CONV = | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 11 | sig | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 12 | val to_case: Proof.context -> thm list -> thm | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 13 | val gen_to_simps: Proof.context -> thm list -> thm -> thm list | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 14 | val to_simps: Proof.context -> thm -> thm list | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 15 | end | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 16 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 17 | structure Simps_Case_Conv: SIMPS_CASE_CONV = | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 18 | struct | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 19 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 20 | (* Collects all type constructors in a type *) | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 21 | fun collect_Tcons (Type (name,Ts)) = name :: maps collect_Tcons Ts | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 22 | | collect_Tcons (TFree _) = [] | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 23 | | collect_Tcons (TVar _) = [] | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 24 | |
| 60702 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 25 | fun get_type_infos ctxt = | 
| 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 26 | maps collect_Tcons | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 27 | #> distinct (op =) | 
| 54401 
f6950854855d
ported 'Simps_Case_Conv' to use new 'Ctr_Sugar' abstraction
 blanchet parents: 
53433diff
changeset | 28 | #> map_filter (Ctr_Sugar.ctr_sugar_of ctxt) | 
| 60702 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 29 | |
| 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 30 | fun get_split_ths ctxt = get_type_infos ctxt #> map #split | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 31 | |
| 59582 | 32 | val strip_eq = Thm.prop_of #> HOLogic.dest_Trueprop #> HOLogic.dest_eq | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 33 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 34 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 35 | local | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 36 | |
| 53429 | 37 | fun transpose [] = [] | 
| 38 | | transpose ([] :: xss) = transpose xss | |
| 39 | | transpose xss = map hd xss :: transpose (map tl xss); | |
| 40 | ||
| 60702 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 41 | fun same_fun single_ctrs (ts as _ $ _ :: _) = | 
| 53429 | 42 | let | 
| 43 | val (fs, argss) = map strip_comb ts |> split_list | |
| 44 | val f = hd fs | |
| 60702 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 45 | fun is_single_ctr (Const (name, _)) = member (op =) single_ctrs name | 
| 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 46 | | is_single_ctr _ = false | 
| 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 47 | in if not (is_single_ctr f) andalso forall (fn x => f = x) fs then SOME (f, argss) else NONE end | 
| 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 48 | | same_fun _ _ = NONE | 
| 53429 | 49 | |
| 50 | (* pats must be non-empty *) | |
| 60702 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 51 | fun split_pat single_ctrs pats ctxt = | 
| 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 52 | case same_fun single_ctrs pats of | 
| 53429 | 53 | NONE => | 
| 54 | let | |
| 55 | val (name, ctxt') = yield_singleton Variable.variant_fixes "x" ctxt | |
| 56 | val var = Free (name, fastype_of (hd pats)) | |
| 57 | in (((var, [var]), map single pats), ctxt') end | |
| 58 | | SOME (f, argss) => | |
| 59 | let | |
| 60 | val (((def_pats, def_frees), case_patss), ctxt') = | |
| 60702 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 61 | split_pats single_ctrs argss ctxt | 
| 53429 | 62 | val def_pat = list_comb (f, def_pats) | 
| 63 | in (((def_pat, flat def_frees), case_patss), ctxt') end | |
| 64 | and | |
| 60702 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 65 | split_pats single_ctrs patss ctxt = | 
| 53429 | 66 | let | 
| 60702 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 67 | val (splitted, ctxt') = fold_map (split_pat single_ctrs) (transpose patss) ctxt | 
| 53429 | 68 | val r = splitted |> split_list |> apfst split_list |> apsnd (transpose #> map flat) | 
| 69 | in (r, ctxt') end | |
| 70 | ||
| 71 | (* | |
| 72 | Takes a list lhss of left hand sides (which are lists of patterns) | |
| 73 | and a list rhss of right hand sides. Returns | |
| 74 | - a single equation with a (nested) case-expression on the rhs | |
| 75 | - a list of all split-thms needed to split the rhs | |
| 76 | Patterns which have the same outer context in all lhss remain | |
| 77 | on the lhs of the computed equation. | |
| 78 | *) | |
| 79 | fun build_case_t fun_t lhss rhss ctxt = | |
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 80 | let | 
| 60702 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 81 | val single_ctrs = | 
| 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 82 | get_type_infos ctxt (map fastype_of (flat lhss)) | 
| 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 83 | |> map_filter (fn ti => case #ctrs ti of [Const (name, _)] => SOME name | _ => NONE) | 
| 53429 | 84 | val (((def_pats, def_frees), case_patss), ctxt') = | 
| 60702 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 85 | split_pats single_ctrs lhss ctxt | 
| 53429 | 86 | val pattern = map HOLogic.mk_tuple case_patss | 
| 87 | val case_arg = HOLogic.mk_tuple (flat def_frees) | |
| 88 | val cases = Case_Translation.make_case ctxt' Case_Translation.Warning Name.context | |
| 89 | case_arg (pattern ~~ rhss) | |
| 60702 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 90 | val split_thms = get_split_ths ctxt' [fastype_of case_arg] | 
| 53429 | 91 | val t = (list_comb (fun_t, def_pats), cases) | 
| 92 | |> HOLogic.mk_eq | |
| 93 | |> HOLogic.mk_Trueprop | |
| 94 | in ((t, split_thms), ctxt') end | |
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 95 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 96 | fun tac ctxt {splits, intros, defs} =
 | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 97 | let val ctxt' = Classical.addSIs (ctxt, intros) in | 
| 58956 
a816aa3ff391
proper context for compose_tac, Splitter.split_tac (relevant for unify trace options);
 wenzelm parents: 
58028diff
changeset | 98 | REPEAT_DETERM1 (FIRSTGOAL (split_tac ctxt splits)) | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 99 | THEN Local_Defs.unfold_tac ctxt defs | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 100 | THEN safe_tac ctxt' | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 101 | end | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 102 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 103 | fun import [] ctxt = ([], ctxt) | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 104 | | import (thm :: thms) ctxt = | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 105 | let | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 106 | val fun_ct = strip_eq #> fst #> strip_comb #> fst #> Logic.mk_term | 
| 59621 
291934bac95e
Thm.cterm_of and Thm.ctyp_of operate on local context;
 wenzelm parents: 
59582diff
changeset | 107 | #> Thm.cterm_of ctxt | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 108 | val ct = fun_ct thm | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 109 | val cts = map fun_ct thms | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 110 | val pairs = map (fn s => (s,ct)) cts | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 111 | val thms' = map (fn (th,p) => Thm.instantiate (Thm.match p) th) (thms ~~ pairs) | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 112 | in Variable.import true (thm :: thms') ctxt |> apfst snd end | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 113 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 114 | in | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 115 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 116 | (* | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 117 | For a list | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 118 | f p_11 ... p_1n = t1 | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 119 | f p_21 ... p_2n = t2 | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 120 | ... | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 121 | f p_mn ... p_mn = tm | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 122 | of theorems, prove a single theorem | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 123 | f x1 ... xn = t | 
| 53429 | 124 | where t is a (nested) case expression. f must not be a function | 
| 125 | application. Moreover, the terms p_11, ..., p_mn must be non-overlapping | |
| 126 | datatype patterns. The patterns must be exhausting up to common constructor | |
| 127 | contexts. | |
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 128 | *) | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 129 | fun to_case ctxt ths = | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 130 | let | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 131 | val (iths, ctxt') = import ths ctxt | 
| 53429 | 132 | val fun_t = hd iths |> strip_eq |> fst |> head_of | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 133 | val eqs = map (strip_eq #> apfst (snd o strip_comb)) iths | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 134 | |
| 59650 | 135 | fun hide_rhs ((pat, rhs), name) lthy = | 
| 136 | let | |
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 137 | val frees = fold Term.add_frees pat [] | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 138 | val abs_rhs = fold absfree frees rhs | 
| 63344 | 139 | val ([(f, (_, def))], lthy') = lthy | 
| 63352 | 140 | |> Local_Defs.define [((Binding.name name, NoSyn), (Binding.empty_atts, abs_rhs))] | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 141 | in ((list_comb (f, map Free (rev frees)), def), lthy') end | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 142 | |
| 59650 | 143 | val ((def_ts, def_thms), ctxt2) = | 
| 144 | let val names = Name.invent (Variable.names_of ctxt') "rhs" (length eqs) | |
| 53429 | 145 | in fold_map hide_rhs (eqs ~~ names) ctxt' |> apfst split_list end | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 146 | |
| 53429 | 147 | val ((t, split_thms), ctxt3) = build_case_t fun_t (map fst eqs) def_ts ctxt2 | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 148 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 149 |     val th = Goal.prove ctxt3 [] [] t (fn {context=ctxt, ...} =>
 | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 150 |           tac ctxt {splits=split_thms, intros=ths, defs=def_thms})
 | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 151 | in th | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 152 | |> singleton (Proof_Context.export ctxt3 ctxt) | 
| 54883 
dd04a8b654fc
proper context for norm_hhf and derived operations;
 wenzelm parents: 
54401diff
changeset | 153 | |> Goal.norm_result ctxt | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 154 | end | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 155 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 156 | end | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 157 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 158 | local | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 159 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 160 | fun was_split t = | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 161 | let | 
| 56252 | 162 | val is_free_eq_imp = is_Free o fst o HOLogic.dest_eq o fst o HOLogic.dest_imp | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 163 | val get_conjs = HOLogic.dest_conj o HOLogic.dest_Trueprop | 
| 56252 | 164 |     fun dest_alls (Const (@{const_name All}, _) $ Abs (_, _, t)) = dest_alls t
 | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 165 | | dest_alls t = t | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 166 | in forall (is_free_eq_imp o dest_alls) (get_conjs t) end | 
| 56252 | 167 | handle TERM _ => false | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 168 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 169 | fun apply_split ctxt split thm = Seq.of_list | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 170 | let val ((_,thm'), ctxt') = Variable.import false [thm] ctxt in | 
| 59582 | 171 | (Variable.export ctxt' ctxt) (filter (was_split o Thm.prop_of) (thm' RL [split])) | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 172 | end | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 173 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 174 | fun forward_tac rules t = Seq.of_list ([t] RL rules) | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 175 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 176 | val refl_imp = refl RSN (2, mp) | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 177 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 178 | val get_rules_once_split = | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 179 | REPEAT (forward_tac [conjunct1, conjunct2]) | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 180 | THEN REPEAT (forward_tac [spec]) | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 181 | THEN (forward_tac [refl_imp]) | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 182 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 183 | fun do_split ctxt split = | 
| 60355 
ccafd7d193e7
simps_of_case: Better error if split rule is not an equality
 noschinl parents: 
60354diff
changeset | 184 | case try op RS (split, iffD1) of | 
| 
ccafd7d193e7
simps_of_case: Better error if split rule is not an equality
 noschinl parents: 
60354diff
changeset | 185 |     NONE => raise TERM ("malformed split rule", [Thm.prop_of split])
 | 
| 
ccafd7d193e7
simps_of_case: Better error if split rule is not an equality
 noschinl parents: 
60354diff
changeset | 186 | | SOME split' => | 
| 
ccafd7d193e7
simps_of_case: Better error if split rule is not an equality
 noschinl parents: 
60354diff
changeset | 187 | let val split_rhs = Thm.concl_of (hd (snd (fst (Variable.import false [split'] ctxt)))) | 
| 
ccafd7d193e7
simps_of_case: Better error if split rule is not an equality
 noschinl parents: 
60354diff
changeset | 188 | in if was_split split_rhs | 
| 
ccafd7d193e7
simps_of_case: Better error if split rule is not an equality
 noschinl parents: 
60354diff
changeset | 189 | then DETERM (apply_split ctxt split') THEN get_rules_once_split | 
| 
ccafd7d193e7
simps_of_case: Better error if split rule is not an equality
 noschinl parents: 
60354diff
changeset | 190 |          else raise TERM ("malformed split rule", [split_rhs])
 | 
| 
ccafd7d193e7
simps_of_case: Better error if split rule is not an equality
 noschinl parents: 
60354diff
changeset | 191 | end | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 192 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 193 | val atomize_meta_eq = forward_tac [meta_eq_to_obj_eq] | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 194 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 195 | in | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 196 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 197 | fun gen_to_simps ctxt splitthms thm = | 
| 60354 
235d65be79c9
simps_of_case: allow Drule.dummy_thm as ignored split rule
 noschinl parents: 
59936diff
changeset | 198 | let val splitthms' = filter (fn t => not (Thm.eq_thm (t, Drule.dummy_thm))) splitthms | 
| 
235d65be79c9
simps_of_case: allow Drule.dummy_thm as ignored split rule
 noschinl parents: 
59936diff
changeset | 199 | in | 
| 
235d65be79c9
simps_of_case: allow Drule.dummy_thm as ignored split rule
 noschinl parents: 
59936diff
changeset | 200 | Seq.list_of ((TRY atomize_meta_eq THEN (REPEAT (FIRST (map (do_split ctxt) splitthms')))) thm) | 
| 
235d65be79c9
simps_of_case: allow Drule.dummy_thm as ignored split rule
 noschinl parents: 
59936diff
changeset | 201 | end | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 202 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 203 | fun to_simps ctxt thm = | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 204 | let | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 205 | val T = thm |> strip_eq |> fst |> strip_comb |> fst |> fastype_of | 
| 60702 
5e03e1bd1be0
case_of_simps: do not split for types with a single constructor
 noschinl parents: 
60355diff
changeset | 206 | val splitthms = get_split_ths ctxt [T] | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 207 | in gen_to_simps ctxt splitthms thm end | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 208 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 209 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 210 | end | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 211 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 212 | fun case_of_simps_cmd (bind, thms_ref) lthy = | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 213 | let | 
| 55997 
9dc5ce83202c
modernized Attrib.check_name/check_src similar to methods (see also a989bdaf8121);
 wenzelm parents: 
54883diff
changeset | 214 | val bind' = apsnd (map (Attrib.check_src lthy)) bind | 
| 61813 | 215 | val thm = Attrib.eval_thms lthy thms_ref |> to_case lthy | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 216 | in | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 217 | Local_Theory.note (bind', [thm]) lthy |> snd | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 218 | end | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 219 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 220 | fun simps_of_case_cmd ((bind, thm_ref), splits_ref) lthy = | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 221 | let | 
| 55997 
9dc5ce83202c
modernized Attrib.check_name/check_src similar to methods (see also a989bdaf8121);
 wenzelm parents: 
54883diff
changeset | 222 | val bind' = apsnd (map (Attrib.check_src lthy)) bind | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 223 | val thm = singleton (Attrib.eval_thms lthy) thm_ref | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 224 | val simps = if null splits_ref | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 225 | then to_simps lthy thm | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 226 | else gen_to_simps lthy (Attrib.eval_thms lthy splits_ref) thm | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 227 | in | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 228 | Local_Theory.note (bind', simps) lthy |> snd | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 229 | end | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 230 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 231 | val _ = | 
| 59936 
b8ffc3dc9e24
@{command_spec} is superseded by @{command_keyword};
 wenzelm parents: 
59650diff
changeset | 232 |   Outer_Syntax.local_theory @{command_keyword case_of_simps}
 | 
| 57628 | 233 | "turn a list of equations into a case expression" | 
| 62969 | 234 | (Parse_Spec.opt_thm_name ":" -- Parse.thms1 >> case_of_simps_cmd) | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 235 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 236 | val parse_splits = @{keyword "("} |-- Parse.reserved "splits" |-- @{keyword ":"} |--
 | 
| 62969 | 237 |   Parse.thms1 --| @{keyword ")"}
 | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 238 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 239 | val _ = | 
| 59936 
b8ffc3dc9e24
@{command_spec} is superseded by @{command_keyword};
 wenzelm parents: 
59650diff
changeset | 240 |   Outer_Syntax.local_theory @{command_keyword simps_of_case}
 | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 241 | "perform case split on rule" | 
| 62969 | 242 | (Parse_Spec.opt_thm_name ":" -- Parse.thm -- | 
| 53426 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 243 | Scan.optional parse_splits [] >> simps_of_case_cmd) | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 244 | |
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 245 | end | 
| 
92db671e0ac6
added simps_of_case and case_of_simps to convert between simps and case rules
 noschinl parents: diff
changeset | 246 |