author | blanchet |
Mon, 15 Sep 2014 11:17:44 +0200 | |
changeset 58337 | 568fb4e382c9 |
parent 58335 | a5a3b576fcfb |
child 58338 | d109244b89aa |
permissions | -rw-r--r-- |
56638 | 1 |
(* Title: HOL/Tools/BNF/bnf_lfp_size.ML |
2 |
Author: Jasmin Blanchette, TU Muenchen |
|
3 |
Copyright 2014 |
|
4 |
||
58315 | 5 |
Generation of size functions for datatypes. |
56638 | 6 |
*) |
7 |
||
56642
15cd15f9b40c
allow registration of custom size functions for BNF-based datatypes
blanchet
parents:
56640
diff
changeset
|
8 |
signature BNF_LFP_SIZE = |
15cd15f9b40c
allow registration of custom size functions for BNF-based datatypes
blanchet
parents:
56640
diff
changeset
|
9 |
sig |
58191 | 10 |
val size_plugin: string |
56651 | 11 |
val register_size: string -> string -> thm list -> thm list -> local_theory -> local_theory |
12 |
val register_size_global: string -> string -> thm list -> thm list -> theory -> theory |
|
58179 | 13 |
val size_of: Proof.context -> string -> (string * (thm list * thm list)) option |
14 |
val size_of_global: theory -> string -> (string * (thm list * thm list)) option |
|
56642
15cd15f9b40c
allow registration of custom size functions for BNF-based datatypes
blanchet
parents:
56640
diff
changeset
|
15 |
end; |
15cd15f9b40c
allow registration of custom size functions for BNF-based datatypes
blanchet
parents:
56640
diff
changeset
|
16 |
|
15cd15f9b40c
allow registration of custom size functions for BNF-based datatypes
blanchet
parents:
56640
diff
changeset
|
17 |
structure BNF_LFP_Size : BNF_LFP_SIZE = |
56638 | 18 |
struct |
19 |
||
20 |
open BNF_Util |
|
56640
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
21 |
open BNF_Tactics |
56638 | 22 |
open BNF_Def |
58179 | 23 |
open BNF_FP_Def_Sugar |
56638 | 24 |
|
58337 | 25 |
val size_plugin = "size"; |
58186 | 26 |
|
58337 | 27 |
val size_N = "size_"; |
56638 | 28 |
|
58337 | 29 |
val rec_o_mapN = "rec_o_map"; |
30 |
val sizeN = "size"; |
|
31 |
val size_o_mapN = "size_o_map"; |
|
56638 | 32 |
|
56651 | 33 |
val nitpicksimp_attrs = @{attributes [nitpick_simp]}; |
34 |
val simp_attrs = @{attributes [simp]}; |
|
35 |
||
36 |
structure Data = Generic_Data |
|
56638 | 37 |
( |
38 |
type T = (string * (thm list * thm list)) Symtab.table; |
|
39 |
val empty = Symtab.empty; |
|
40 |
val extend = I |
|
41 |
fun merge data = Symtab.merge (K true) data; |
|
42 |
); |
|
43 |
||
56642
15cd15f9b40c
allow registration of custom size functions for BNF-based datatypes
blanchet
parents:
56640
diff
changeset
|
44 |
fun register_size T_name size_name size_simps size_o_maps = |
56651 | 45 |
Context.proof_map (Data.map (Symtab.update (T_name, (size_name, (size_simps, size_o_maps))))); |
56643
41d3596d8a64
move size hooks together, with new one preceding old one and sharing same theory data
blanchet
parents:
56642
diff
changeset
|
46 |
|
56651 | 47 |
fun register_size_global T_name size_name size_simps size_o_maps = |
48 |
Context.theory_map (Data.map (Symtab.update (T_name, (size_name, (size_simps, size_o_maps))))); |
|
49 |
||
58179 | 50 |
val size_of = Symtab.lookup o Data.get o Context.Proof; |
51 |
val size_of_global = Symtab.lookup o Data.get o Context.Theory; |
|
56642
15cd15f9b40c
allow registration of custom size functions for BNF-based datatypes
blanchet
parents:
56640
diff
changeset
|
52 |
|
56638 | 53 |
fun mk_plus_nat (t1, t2) = Const (@{const_name Groups.plus}, |
54 |
HOLogic.natT --> HOLogic.natT --> HOLogic.natT) $ t1 $ t2; |
|
55 |
||
56 |
fun mk_to_natT T = T --> HOLogic.natT; |
|
57 |
||
58337 | 58 |
fun mk_abs_zero_nat T = Term.absdummy T HOLogic.zero; |
56638 | 59 |
|
56640
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
60 |
fun pointfill ctxt th = unfold_thms ctxt [o_apply] (th RS fun_cong); |
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
61 |
|
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
62 |
fun mk_unabs_def_unused_0 n = |
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
63 |
funpow n (fn thm => thm RS @{thm fun_cong_unused_0} handle THM _ => thm RS fun_cong); |
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
64 |
|
58180 | 65 |
val rec_o_map_simps = |
57993 | 66 |
@{thms o_def[abs_def] id_def case_prod_app case_sum_map_sum case_prod_map_prod |
58181 | 67 |
BNF_Composition.id_bnf_def}; |
56638 | 68 |
|
57399 | 69 |
fun mk_rec_o_map_tac ctxt rec_def pre_map_defs live_nesting_map_ident0s abs_inverses |
70 |
ctor_rec_o_map = |
|
56640
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
71 |
unfold_thms_tac ctxt [rec_def] THEN |
57890
1e13f63fb452
use Goal.prove_sorry instead of Goal.prove where possible (= no schematics in goal and tactic is expected to succeed)
traytel
parents:
57631
diff
changeset
|
72 |
HEADGOAL (rtac (ctor_rec_o_map RS trans) THEN' |
1e13f63fb452
use Goal.prove_sorry instead of Goal.prove where possible (= no schematics in goal and tactic is expected to succeed)
traytel
parents:
57631
diff
changeset
|
73 |
CONVERSION Thm.eta_long_conversion THEN' |
1e13f63fb452
use Goal.prove_sorry instead of Goal.prove where possible (= no schematics in goal and tactic is expected to succeed)
traytel
parents:
57631
diff
changeset
|
74 |
asm_simp_tac (ss_only (pre_map_defs @ |
58180 | 75 |
distinct Thm.eq_thm_prop (live_nesting_map_ident0s @ abs_inverses) @ rec_o_map_simps) |
57993 | 76 |
ctxt)); |
56638 | 77 |
|
58180 | 78 |
val size_o_map_simps = @{thms prod_inj_map inj_on_id snd_comp_apfst[unfolded apfst_def]}; |
56640
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
79 |
|
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
80 |
fun mk_size_o_map_tac ctxt size_def rec_o_map inj_maps size_maps = |
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
81 |
unfold_thms_tac ctxt [size_def] THEN |
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
82 |
HEADGOAL (rtac (rec_o_map RS trans) THEN' |
58180 | 83 |
asm_simp_tac (ss_only (inj_maps @ size_maps @ size_o_map_simps) ctxt)) THEN |
56645
a16d294f7e3f
prevent tactic failures by detecting and ignoring BNFs with no 'size' functions early
blanchet
parents:
56643
diff
changeset
|
84 |
IF_UNSOLVED (unfold_thms_tac ctxt @{thms o_def} THEN HEADGOAL (rtac refl)); |
56638 | 85 |
|
58179 | 86 |
fun generate_datatype_size (fp_sugars as ({T = Type (_, As), BT = Type (_, Bs), fp = Least_FP, |
87 |
fp_res = {bnfs = fp_bnfs, xtor_co_rec_o_map_thms = ctor_rec_o_maps, ...}, fp_nesting_bnfs, |
|
88 |
live_nesting_bnfs, ...} : fp_sugar) :: _) lthy0 = |
|
89 |
let |
|
90 |
val data = Data.get (Context.Proof lthy0); |
|
56651 | 91 |
|
58179 | 92 |
val Ts = map #T fp_sugars |
93 |
val T_names = map (fst o dest_Type) Ts; |
|
94 |
val nn = length Ts; |
|
56640
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
95 |
|
58179 | 96 |
val B_ify = Term.typ_subst_atomic (As ~~ Bs); |
56651 | 97 |
|
58179 | 98 |
val recs = map #co_rec fp_sugars; |
99 |
val rec_thmss = map #co_rec_thms fp_sugars; |
|
100 |
val rec_Ts as rec_T1 :: _ = map fastype_of recs; |
|
101 |
val rec_arg_Ts = binder_fun_types rec_T1; |
|
102 |
val Cs = map body_type rec_Ts; |
|
103 |
val Cs_rho = map (rpair HOLogic.natT) Cs; |
|
104 |
val substCnatT = Term.subst_atomic_types Cs_rho; |
|
56651 | 105 |
|
58179 | 106 |
val f_Ts = map mk_to_natT As; |
107 |
val f_TsB = map mk_to_natT Bs; |
|
108 |
val num_As = length As; |
|
56651 | 109 |
|
58179 | 110 |
fun variant_names n pre = fst (Variable.variant_fixes (replicate n pre) lthy0); |
56651 | 111 |
|
58179 | 112 |
val f_names = variant_names num_As "f"; |
113 |
val fs = map2 (curry Free) f_names f_Ts; |
|
114 |
val fsB = map2 (curry Free) f_names f_TsB; |
|
115 |
val As_fs = As ~~ fs; |
|
56638 | 116 |
|
58179 | 117 |
val size_bs = |
118 |
map ((fn base => Binding.qualify false base (Binding.name (prefix size_N base))) o |
|
119 |
Long_Name.base_name) T_names; |
|
56638 | 120 |
|
58208 | 121 |
fun is_prod_C @{type_name prod} [_, T'] = member (op =) Cs T' |
122 |
| is_prod_C _ _ = false; |
|
56651 | 123 |
|
58179 | 124 |
fun mk_size_of_typ (T as TFree _) = |
125 |
pair (case AList.lookup (op =) As_fs T of |
|
126 |
SOME f => f |
|
127 |
| NONE => if member (op =) Cs T then Term.absdummy T (Bound 0) else mk_abs_zero_nat T) |
|
128 |
| mk_size_of_typ (T as Type (s, Ts)) = |
|
58208 | 129 |
if is_prod_C s Ts then |
58179 | 130 |
pair (snd_const T) |
131 |
else if exists (exists_subtype_in (As @ Cs)) Ts then |
|
132 |
(case Symtab.lookup data s of |
|
133 |
SOME (size_name, (_, size_o_maps)) => |
|
134 |
let |
|
135 |
val (args, size_o_mapss') = split_list (map (fn T => mk_size_of_typ T []) Ts); |
|
136 |
val size_const = Const (size_name, map fastype_of args ---> mk_to_natT T); |
|
137 |
in |
|
138 |
fold (union Thm.eq_thm_prop) (size_o_maps :: size_o_mapss') |
|
139 |
#> pair (Term.list_comb (size_const, args)) |
|
140 |
end |
|
141 |
| _ => pair (mk_abs_zero_nat T)) |
|
142 |
else |
|
143 |
pair (mk_abs_zero_nat T); |
|
56651 | 144 |
|
58179 | 145 |
fun mk_size_of_arg t = |
146 |
mk_size_of_typ (fastype_of t) #>> (fn s => substCnatT (betapply (s, t))); |
|
56638 | 147 |
|
58179 | 148 |
fun mk_size_arg rec_arg_T size_o_maps = |
149 |
let |
|
150 |
val x_Ts = binder_types rec_arg_T; |
|
151 |
val m = length x_Ts; |
|
152 |
val x_names = variant_names m "x"; |
|
153 |
val xs = map2 (curry Free) x_names x_Ts; |
|
154 |
val (summands, size_o_maps') = |
|
155 |
fold_map mk_size_of_arg xs size_o_maps |
|
58337 | 156 |
|>> remove (op =) HOLogic.zero; |
58179 | 157 |
val sum = |
158 |
if null summands then HOLogic.zero |
|
159 |
else foldl1 mk_plus_nat (summands @ [HOLogic.Suc_zero]); |
|
56640
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
160 |
in |
58179 | 161 |
(fold_rev Term.lambda (map substCnatT xs) sum, size_o_maps') |
56640
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
162 |
end; |
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
163 |
|
58179 | 164 |
fun mk_size_rhs recx size_o_maps = |
165 |
fold_map mk_size_arg rec_arg_Ts size_o_maps |
|
166 |
|>> (fn args => fold_rev Term.lambda fs (Term.list_comb (substCnatT recx, args))); |
|
167 |
||
168 |
val maybe_conceal_def_binding = Thm.def_binding |
|
58208 | 169 |
#> not (Config.get lthy0 bnf_note_all) ? Binding.conceal; |
58179 | 170 |
|
171 |
val (size_rhss, nested_size_o_maps) = fold_map mk_size_rhs recs []; |
|
172 |
val size_Ts = map fastype_of size_rhss; |
|
173 |
||
174 |
val ((raw_size_consts, raw_size_defs), (lthy1', lthy1)) = lthy0 |
|
175 |
|> apfst split_list o fold_map2 (fn b => fn rhs => |
|
176 |
Local_Theory.define ((b, NoSyn), ((maybe_conceal_def_binding b, []), rhs)) |
|
177 |
#>> apsnd snd) |
|
178 |
size_bs size_rhss |
|
179 |
||> `Local_Theory.restore; |
|
180 |
||
181 |
val phi = Proof_Context.export_morphism lthy1 lthy1'; |
|
182 |
||
183 |
val size_defs = map (Morphism.thm phi) raw_size_defs; |
|
184 |
||
185 |
val size_consts0 = map (Morphism.term phi) raw_size_consts; |
|
186 |
val size_consts = map2 retype_const_or_free size_Ts size_consts0; |
|
187 |
val size_constsB = map (Term.map_types B_ify) size_consts; |
|
188 |
||
189 |
val zeros = map mk_abs_zero_nat As; |
|
190 |
||
191 |
val overloaded_size_rhss = map (fn c => Term.list_comb (c, zeros)) size_consts; |
|
192 |
val overloaded_size_Ts = map fastype_of overloaded_size_rhss; |
|
193 |
val overloaded_size_consts = map (curry Const @{const_name size}) overloaded_size_Ts; |
|
194 |
val overloaded_size_def_bs = |
|
195 |
map (maybe_conceal_def_binding o Binding.suffix_name "_overloaded") size_bs; |
|
196 |
||
197 |
fun define_overloaded_size def_b lhs0 rhs lthy = |
|
198 |
let |
|
199 |
val Free (c, _) = Syntax.check_term lthy lhs0; |
|
200 |
val (thm, lthy') = lthy |
|
201 |
|> Local_Theory.define ((Binding.name c, NoSyn), ((def_b, []), rhs)) |
|
202 |
|-> (fn (t, (_, thm)) => Spec_Rules.add Spec_Rules.Equational ([t], [thm]) #> pair thm); |
|
203 |
val ctxt_thy = Proof_Context.init_global (Proof_Context.theory_of lthy'); |
|
204 |
val thm' = singleton (Proof_Context.export lthy' ctxt_thy) thm; |
|
205 |
in (thm', lthy') end; |
|
206 |
||
207 |
val (overloaded_size_defs, lthy2) = lthy1 |
|
208 |
|> Local_Theory.background_theory_result |
|
209 |
(Class.instantiation (T_names, map dest_TFree As, [HOLogic.class_size]) |
|
210 |
#> fold_map3 define_overloaded_size overloaded_size_def_bs overloaded_size_consts |
|
211 |
overloaded_size_rhss |
|
212 |
##> Class.prove_instantiation_instance (K (Class.intro_classes_tac [])) |
|
213 |
##> Local_Theory.exit_global); |
|
56638 | 214 |
|
58179 | 215 |
val size_defs' = |
216 |
map (mk_unabs_def (num_As + 1) o (fn thm => thm RS meta_eq_to_obj_eq)) size_defs; |
|
217 |
val size_defs_unused_0 = |
|
218 |
map (mk_unabs_def_unused_0 (num_As + 1) o (fn thm => thm RS meta_eq_to_obj_eq)) size_defs; |
|
219 |
val overloaded_size_defs' = |
|
220 |
map (mk_unabs_def 1 o (fn thm => thm RS meta_eq_to_obj_eq)) overloaded_size_defs; |
|
221 |
||
222 |
val all_overloaded_size_defs = overloaded_size_defs @ |
|
223 |
(Spec_Rules.retrieve lthy0 @{const size ('a)} |
|
224 |
|> map_filter (try (fn (Spec_Rules.Equational, (_, [thm])) => thm))); |
|
225 |
||
226 |
val nested_size_maps = map (pointfill lthy2) nested_size_o_maps @ nested_size_o_maps; |
|
227 |
val all_inj_maps = map inj_map_of_bnf (fp_bnfs @ fp_nesting_bnfs @ live_nesting_bnfs) |
|
228 |
|> distinct Thm.eq_thm_prop; |
|
229 |
||
230 |
fun derive_size_simp size_def' simp0 = |
|
231 |
(trans OF [size_def', simp0]) |
|
232 |
|> Simplifier.asm_full_simplify (ss_only (@{thms inj_on_convol_ident id_def o_def |
|
233 |
snd_conv} @ all_inj_maps @ nested_size_maps) lthy2) |
|
234 |
|> fold_thms lthy2 size_defs_unused_0; |
|
235 |
||
236 |
fun derive_overloaded_size_simp overloaded_size_def' simp0 = |
|
237 |
(trans OF [overloaded_size_def', simp0]) |
|
238 |
|> unfold_thms lthy2 @{thms add_0_left add_0_right} |
|
239 |
|> fold_thms lthy2 all_overloaded_size_defs; |
|
240 |
||
241 |
val size_simpss = map2 (map o derive_size_simp) size_defs' rec_thmss; |
|
242 |
val size_simps = flat size_simpss; |
|
243 |
val overloaded_size_simpss = |
|
244 |
map2 (map o derive_overloaded_size_simp) overloaded_size_defs' size_simpss; |
|
245 |
val size_thmss = map2 append size_simpss overloaded_size_simpss; |
|
246 |
||
247 |
val ABs = As ~~ Bs; |
|
248 |
val g_names = variant_names num_As "g"; |
|
249 |
val gs = map2 (curry Free) g_names (map (op -->) ABs); |
|
250 |
||
251 |
val liveness = map (op <>) ABs; |
|
252 |
val live_gs = AList.find (op =) (gs ~~ liveness) true; |
|
253 |
val live = length live_gs; |
|
254 |
||
255 |
val maps0 = map map_of_bnf fp_bnfs; |
|
256 |
||
257 |
val (rec_o_map_thmss, size_o_map_thmss) = |
|
258 |
if live = 0 then |
|
259 |
`I (replicate nn []) |
|
260 |
else |
|
261 |
let |
|
262 |
val pre_bnfs = map #pre_bnf fp_sugars; |
|
263 |
val pre_map_defs = map map_def_of_bnf pre_bnfs; |
|
264 |
val live_nesting_map_ident0s = map map_ident0_of_bnf live_nesting_bnfs; |
|
265 |
val abs_inverses = map (#abs_inverse o #absT_info) fp_sugars; |
|
266 |
val rec_defs = map #co_rec_def fp_sugars; |
|
267 |
||
268 |
val gmaps = map (fn map0 => Term.list_comb (mk_map live As Bs map0, live_gs)) maps0; |
|
57631
959caab43a3d
use the noted theorem whenever possible, also in 'BNF_Def'
blanchet
parents:
57399
diff
changeset
|
269 |
|
58179 | 270 |
val num_rec_args = length rec_arg_Ts; |
271 |
val h_Ts = map B_ify rec_arg_Ts; |
|
272 |
val h_names = variant_names num_rec_args "h"; |
|
273 |
val hs = map2 (curry Free) h_names h_Ts; |
|
274 |
val hrecs = map (fn recx => Term.list_comb (Term.map_types B_ify recx, hs)) recs; |
|
275 |
||
276 |
val rec_o_map_lhss = map2 (curry HOLogic.mk_comp) hrecs gmaps; |
|
277 |
||
278 |
val ABgs = ABs ~~ gs; |
|
279 |
||
280 |
fun mk_rec_arg_arg (x as Free (_, T)) = |
|
281 |
let val U = B_ify T in |
|
282 |
if T = U then x else build_map lthy2 [] (the o AList.lookup (op =) ABgs) (T, U) $ x |
|
283 |
end; |
|
284 |
||
285 |
fun mk_rec_o_map_arg rec_arg_T h = |
|
286 |
let |
|
287 |
val x_Ts = binder_types rec_arg_T; |
|
288 |
val m = length x_Ts; |
|
289 |
val x_names = variant_names m "x"; |
|
290 |
val xs = map2 (curry Free) x_names x_Ts; |
|
291 |
val xs' = map mk_rec_arg_arg xs; |
|
292 |
in |
|
293 |
fold_rev Term.lambda xs (Term.list_comb (h, xs')) |
|
294 |
end; |
|
295 |
||
296 |
fun mk_rec_o_map_rhs recx = |
|
297 |
let val args = map2 mk_rec_o_map_arg rec_arg_Ts hs in |
|
298 |
Term.list_comb (recx, args) |
|
299 |
end; |
|
300 |
||
301 |
val rec_o_map_rhss = map mk_rec_o_map_rhs recs; |
|
302 |
||
303 |
val rec_o_map_goals = |
|
304 |
map2 (fold_rev (fold_rev Logic.all) [gs, hs] o HOLogic.mk_Trueprop oo |
|
305 |
curry HOLogic.mk_eq) rec_o_map_lhss rec_o_map_rhss; |
|
306 |
val rec_o_map_thms = |
|
307 |
map3 (fn goal => fn rec_def => fn ctor_rec_o_map => |
|
308 |
Goal.prove_sorry lthy2 [] [] goal (fn {context = ctxt, ...} => |
|
309 |
mk_rec_o_map_tac ctxt rec_def pre_map_defs live_nesting_map_ident0s abs_inverses |
|
310 |
ctor_rec_o_map) |
|
311 |
|> Thm.close_derivation) |
|
312 |
rec_o_map_goals rec_defs ctor_rec_o_maps; |
|
313 |
||
314 |
val size_o_map_conds = |
|
315 |
if exists (can Logic.dest_implies o Thm.prop_of) nested_size_o_maps then |
|
316 |
map (HOLogic.mk_Trueprop o mk_inj) live_gs |
|
317 |
else |
|
318 |
[]; |
|
319 |
||
320 |
val fsizes = map (fn size_constB => Term.list_comb (size_constB, fsB)) size_constsB; |
|
321 |
val size_o_map_lhss = map2 (curry HOLogic.mk_comp) fsizes gmaps; |
|
57631
959caab43a3d
use the noted theorem whenever possible, also in 'BNF_Def'
blanchet
parents:
57399
diff
changeset
|
322 |
|
58179 | 323 |
val fgs = map2 (fn fB => fn g as Free (_, Type (_, [A, B])) => |
324 |
if A = B then fB else HOLogic.mk_comp (fB, g)) fsB gs; |
|
325 |
val size_o_map_rhss = map (fn c => Term.list_comb (c, fgs)) size_consts; |
|
326 |
||
327 |
val size_o_map_goals = |
|
328 |
map2 (fold_rev (fold_rev Logic.all) [fsB, gs] o |
|
329 |
curry Logic.list_implies size_o_map_conds o HOLogic.mk_Trueprop oo |
|
330 |
curry HOLogic.mk_eq) size_o_map_lhss size_o_map_rhss; |
|
331 |
||
332 |
(* The "size o map" theorem generation will fail if "nested_size_maps" is incomplete, |
|
333 |
which occurs when there is recursion through non-datatypes. In this case, we simply |
|
334 |
avoid generating the theorem. The resulting characteristic lemmas are then expressed |
|
335 |
in terms of "map", which is not the end of the world. *) |
|
336 |
val size_o_map_thmss = |
|
337 |
map3 (fn goal => fn size_def => the_list o try (fn rec_o_map => |
|
338 |
Goal.prove (*no sorry*) lthy2 [] [] goal (fn {context = ctxt, ...} => |
|
339 |
mk_size_o_map_tac ctxt size_def rec_o_map all_inj_maps nested_size_maps) |
|
340 |
|> Thm.close_derivation)) |
|
341 |
size_o_map_goals size_defs rec_o_map_thms |
|
342 |
in |
|
343 |
(map single rec_o_map_thms, size_o_map_thmss) |
|
344 |
end; |
|
345 |
||
58335
a5a3b576fcfb
generate 'code' attribute only if 'code' plugin is enabled
blanchet
parents:
58315
diff
changeset
|
346 |
(* Ideally, the "[code]" attribute would be generated only if the "code" plugin is enabled. *) |
a5a3b576fcfb
generate 'code' attribute only if 'code' plugin is enabled
blanchet
parents:
58315
diff
changeset
|
347 |
val code_attrs = Code.add_default_eqn_attrib; |
a5a3b576fcfb
generate 'code' attribute only if 'code' plugin is enabled
blanchet
parents:
58315
diff
changeset
|
348 |
|
58179 | 349 |
val massage_multi_notes = |
350 |
maps (fn (thmN, thmss, attrs) => |
|
351 |
map2 (fn T_name => fn thms => |
|
352 |
((Binding.qualify true (Long_Name.base_name T_name) (Binding.name thmN), attrs), |
|
353 |
[(thms, [])])) |
|
354 |
T_names thmss) |
|
355 |
#> filter_out (null o fst o hd o snd); |
|
356 |
||
357 |
val notes = |
|
358 |
[(rec_o_mapN, rec_o_map_thmss, []), |
|
58335
a5a3b576fcfb
generate 'code' attribute only if 'code' plugin is enabled
blanchet
parents:
58315
diff
changeset
|
359 |
(sizeN, size_thmss, code_attrs :: nitpicksimp_attrs @ simp_attrs), |
58179 | 360 |
(size_o_mapN, size_o_map_thmss, [])] |
361 |
|> massage_multi_notes; |
|
362 |
||
363 |
val (noted, lthy3) = |
|
364 |
lthy2 |
|
365 |
|> Spec_Rules.add Spec_Rules.Equational (size_consts, size_simps) |
|
366 |
|> Local_Theory.notes notes; |
|
367 |
||
368 |
val phi0 = substitute_noted_thm noted; |
|
369 |
in |
|
370 |
lthy3 |
|
371 |
|> Local_Theory.declaration {syntax = false, pervasive = true} |
|
372 |
(fn phi => Data.map (fold2 (fn T_name => fn Const (size_name, _) => |
|
373 |
Symtab.update (T_name, (size_name, |
|
374 |
pairself (map (Morphism.thm (phi0 $> phi))) (size_simps, flat size_o_map_thmss)))) |
|
375 |
T_names size_consts)) |
|
376 |
end |
|
377 |
| generate_datatype_size _ lthy = lthy; |
|
378 |
||
58191 | 379 |
val _ = Theory.setup (fp_sugars_interpretation size_plugin |
58186 | 380 |
(map_local_theory o generate_datatype_size) generate_datatype_size); |
56638 | 381 |
|
382 |
end; |