author | wenzelm |
Sat, 30 Nov 2024 13:40:57 +0100 | |
changeset 81511 | 8cbc8bc6f382 |
parent 81507 | 08574da77b4a |
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 |
62082 | 10 |
val register_size: string -> string -> thm -> thm list -> thm list -> local_theory -> local_theory |
11 |
val register_size_global: string -> string -> thm -> thm list -> thm list -> theory -> theory |
|
12 |
val size_of: Proof.context -> string -> (string * (thm * thm list * thm list)) option |
|
13 |
val size_of_global: theory -> string -> (string * (thm * thm list * thm list)) option |
|
56642
15cd15f9b40c
allow registration of custom size functions for BNF-based datatypes
blanchet
parents:
56640
diff
changeset
|
14 |
end; |
15cd15f9b40c
allow registration of custom size functions for BNF-based datatypes
blanchet
parents:
56640
diff
changeset
|
15 |
|
15cd15f9b40c
allow registration of custom size functions for BNF-based datatypes
blanchet
parents:
56640
diff
changeset
|
16 |
structure BNF_LFP_Size : BNF_LFP_SIZE = |
56638 | 17 |
struct |
18 |
||
19 |
open BNF_Util |
|
56640
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
20 |
open BNF_Tactics |
56638 | 21 |
open BNF_Def |
58179 | 22 |
open BNF_FP_Def_Sugar |
56638 | 23 |
|
58337 | 24 |
val size_N = "size_"; |
25 |
val sizeN = "size"; |
|
58736 | 26 |
val size_genN = "size_gen"; |
58738 | 27 |
val size_gen_o_mapN = "size_gen_o_map"; |
58913 | 28 |
val size_neqN = "size_neq"; |
56638 | 29 |
|
56651 | 30 |
val nitpicksimp_attrs = @{attributes [nitpick_simp]}; |
31 |
val simp_attrs = @{attributes [simp]}; |
|
32 |
||
69593 | 33 |
fun mk_plus_nat (t1, t2) = Const (\<^const_name>\<open>Groups.plus\<close>, |
56638 | 34 |
HOLogic.natT --> HOLogic.natT --> HOLogic.natT) $ t1 $ t2; |
35 |
||
36 |
fun mk_to_natT T = T --> HOLogic.natT; |
|
37 |
||
58337 | 38 |
fun mk_abs_zero_nat T = Term.absdummy T HOLogic.zero; |
56638 | 39 |
|
56640
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
40 |
fun mk_unabs_def_unused_0 n = |
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
41 |
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
|
42 |
|
61786
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
43 |
structure Data = Generic_Data |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
44 |
( |
62082 | 45 |
type T = (string * (thm * thm list * thm list)) Symtab.table; |
61786
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
46 |
val empty = Symtab.empty; |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
47 |
fun merge data = Symtab.merge (K true) data; |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
48 |
); |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
49 |
|
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
50 |
fun check_size_type thy T_name size_name = |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
51 |
let |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
52 |
val n = Sign.arity_number thy T_name; |
81511 | 53 |
val As = map (fn a => TFree (a, \<^sort>\<open>type\<close>)) (Name.invent_global_types n); |
61786
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
54 |
val T = Type (T_name, As); |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
55 |
val size_T = map mk_to_natT As ---> mk_to_natT T; |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
56 |
val size_const = Const (size_name, size_T); |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
57 |
in |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
58 |
can (Thm.global_cterm_of thy) size_const orelse |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
59 |
error ("Constant " ^ quote size_name ^ " registered as size function for " ^ quote T_name ^ |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
60 |
" must have type\n" ^ quote (Syntax.string_of_typ_global thy size_T)) |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
61 |
end; |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
62 |
|
62082 | 63 |
fun register_size T_name size_name overloaded_size_def size_simps size_gen_o_maps lthy = |
61786
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
64 |
(check_size_type (Proof_Context.theory_of lthy) T_name size_name; |
62082 | 65 |
Context.proof_map (Data.map (Symtab.update |
66 |
(T_name, (size_name, (overloaded_size_def, size_simps, size_gen_o_maps))))) |
|
61786
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
67 |
lthy); |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
68 |
|
62082 | 69 |
fun register_size_global T_name size_name overloaded_size_def size_simps size_gen_o_maps thy = |
61786
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
70 |
(check_size_type thy T_name size_name; |
62082 | 71 |
Context.theory_map (Data.map (Symtab.update |
72 |
(T_name, (size_name, (overloaded_size_def, size_simps, size_gen_o_maps))))) |
|
73 |
thy); |
|
61786
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
74 |
|
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
75 |
val size_of = Symtab.lookup o Data.get o Context.Proof; |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
76 |
val size_of_global = Symtab.lookup o Data.get o Context.Theory; |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
77 |
|
62082 | 78 |
fun all_overloaded_size_defs_of ctxt = |
62536
656e9653c645
made 'size' plugin compatible with locales again (and added regression test)
blanchet
parents:
62124
diff
changeset
|
79 |
Symtab.fold (fn (_, (_, (overloaded_size_def, _, _))) => |
656e9653c645
made 'size' plugin compatible with locales again (and added regression test)
blanchet
parents:
62124
diff
changeset
|
80 |
can (Logic.dest_equals o Thm.prop_of) overloaded_size_def ? cons overloaded_size_def) |
62082 | 81 |
(Data.get (Context.Proof ctxt)) []; |
82 |
||
63170 | 83 |
val size_gen_o_map_simps = @{thms inj_on_id snd_comp_apfst[simplified apfst_def]}; |
56640
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
84 |
|
58738 | 85 |
fun mk_size_gen_o_map_tac ctxt size_def rec_o_map inj_maps size_maps = |
56640
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
86 |
unfold_thms_tac ctxt [size_def] THEN |
60728 | 87 |
HEADGOAL (rtac ctxt (rec_o_map RS trans) THEN' |
58738 | 88 |
asm_simp_tac (ss_only (inj_maps @ size_maps @ size_gen_o_map_simps) ctxt)) THEN |
60728 | 89 |
IF_UNSOLVED (unfold_thms_tac ctxt @{thms id_def o_def} THEN HEADGOAL (rtac ctxt refl)); |
56638 | 90 |
|
58913 | 91 |
fun mk_size_neq ctxt cts exhaust sizes = |
60784 | 92 |
HEADGOAL (rtac ctxt (infer_instantiate' ctxt (map SOME cts) exhaust)) THEN |
58913 | 93 |
ALLGOALS (hyp_subst_tac ctxt) THEN |
61760 | 94 |
unfold_thms_tac ctxt (@{thm neq0_conv} :: sizes) THEN |
95 |
ALLGOALS (REPEAT_DETERM o (rtac ctxt @{thm zero_less_Suc} ORELSE' |
|
96 |
rtac ctxt @{thm trans_less_add2})); |
|
58913 | 97 |
|
58179 | 98 |
fun generate_datatype_size (fp_sugars as ({T = Type (_, As), BT = Type (_, Bs), fp = Least_FP, |
63859
dca6fabd8060
make (co)induct component of 'fp_sugar' optional, for the benefit of nonuniform (co)datatypes and other similar extensions
blanchet
parents:
63239
diff
changeset
|
99 |
fp_res = {bnfs = fp_bnfs, ...}, fp_nesting_bnfs, live_nesting_bnfs, |
dca6fabd8060
make (co)induct component of 'fp_sugar' optional, for the benefit of nonuniform (co)datatypes and other similar extensions
blanchet
parents:
63239
diff
changeset
|
100 |
fp_co_induct_sugar = SOME _, ...} : fp_sugar) :: _) |
59145 | 101 |
lthy0 = |
58179 | 102 |
let |
103 |
val data = Data.get (Context.Proof lthy0); |
|
56651 | 104 |
|
58179 | 105 |
val Ts = map #T fp_sugars |
80634
a90ab1ea6458
tuned: more explicit dest_Type_name and dest_Type_args;
wenzelm
parents:
78095
diff
changeset
|
106 |
val T_names = map dest_Type_name Ts; |
58179 | 107 |
val nn = length Ts; |
56640
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
108 |
|
58179 | 109 |
val B_ify = Term.typ_subst_atomic (As ~~ Bs); |
56651 | 110 |
|
63859
dca6fabd8060
make (co)induct component of 'fp_sugar' optional, for the benefit of nonuniform (co)datatypes and other similar extensions
blanchet
parents:
63239
diff
changeset
|
111 |
val recs = map (#co_rec o the o #fp_co_induct_sugar) fp_sugars; |
dca6fabd8060
make (co)induct component of 'fp_sugar' optional, for the benefit of nonuniform (co)datatypes and other similar extensions
blanchet
parents:
63239
diff
changeset
|
112 |
val rec_thmss = map (#co_rec_thms o the o #fp_co_induct_sugar) fp_sugars; |
58179 | 113 |
val rec_Ts as rec_T1 :: _ = map fastype_of recs; |
114 |
val rec_arg_Ts = binder_fun_types rec_T1; |
|
115 |
val Cs = map body_type rec_Ts; |
|
116 |
val Cs_rho = map (rpair HOLogic.natT) Cs; |
|
117 |
val substCnatT = Term.subst_atomic_types Cs_rho; |
|
56651 | 118 |
|
58179 | 119 |
val f_Ts = map mk_to_natT As; |
120 |
val f_TsB = map mk_to_natT Bs; |
|
121 |
val num_As = length As; |
|
56651 | 122 |
|
58179 | 123 |
fun variant_names n pre = fst (Variable.variant_fixes (replicate n pre) lthy0); |
56651 | 124 |
|
58179 | 125 |
val f_names = variant_names num_As "f"; |
126 |
val fs = map2 (curry Free) f_names f_Ts; |
|
127 |
val fsB = map2 (curry Free) f_names f_TsB; |
|
128 |
val As_fs = As ~~ fs; |
|
56638 | 129 |
|
58179 | 130 |
val size_bs = |
131 |
map ((fn base => Binding.qualify false base (Binding.name (prefix size_N base))) o |
|
132 |
Long_Name.base_name) T_names; |
|
56638 | 133 |
|
69593 | 134 |
fun is_prod_C \<^type_name>\<open>prod\<close> [_, T'] = member (op =) Cs T' |
58208 | 135 |
| is_prod_C _ _ = false; |
56651 | 136 |
|
58179 | 137 |
fun mk_size_of_typ (T as TFree _) = |
138 |
pair (case AList.lookup (op =) As_fs T of |
|
139 |
SOME f => f |
|
140 |
| NONE => if member (op =) Cs T then Term.absdummy T (Bound 0) else mk_abs_zero_nat T) |
|
141 |
| mk_size_of_typ (T as Type (s, Ts)) = |
|
58208 | 142 |
if is_prod_C s Ts then |
58179 | 143 |
pair (snd_const T) |
144 |
else if exists (exists_subtype_in (As @ Cs)) Ts then |
|
145 |
(case Symtab.lookup data s of |
|
62082 | 146 |
SOME (size_name, (_, _, size_gen_o_maps)) => |
58179 | 147 |
let |
58738 | 148 |
val (args, size_gen_o_mapss') = fold_map mk_size_of_typ Ts []; |
61786
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
149 |
val size_T = map fastype_of args ---> mk_to_natT T; |
6c42d55097c1
nicer error when the given size function has the wrong type
blanchet
parents:
61760
diff
changeset
|
150 |
val size_const = Const (size_name, size_T); |
58179 | 151 |
in |
58738 | 152 |
append (size_gen_o_maps :: size_gen_o_mapss') |
58179 | 153 |
#> pair (Term.list_comb (size_const, args)) |
154 |
end |
|
155 |
| _ => pair (mk_abs_zero_nat T)) |
|
156 |
else |
|
157 |
pair (mk_abs_zero_nat T); |
|
56651 | 158 |
|
58179 | 159 |
fun mk_size_of_arg t = |
160 |
mk_size_of_typ (fastype_of t) #>> (fn s => substCnatT (betapply (s, t))); |
|
56638 | 161 |
|
58338
d109244b89aa
tuned definition of 'size' function to get nicer properties
blanchet
parents:
58337
diff
changeset
|
162 |
fun is_recursive_or_plain_case Ts = |
d109244b89aa
tuned definition of 'size' function to get nicer properties
blanchet
parents:
58337
diff
changeset
|
163 |
exists (exists_subtype_in Cs) Ts orelse forall (not o exists_subtype_in As) Ts; |
d109244b89aa
tuned definition of 'size' function to get nicer properties
blanchet
parents:
58337
diff
changeset
|
164 |
|
d109244b89aa
tuned definition of 'size' function to get nicer properties
blanchet
parents:
58337
diff
changeset
|
165 |
(* We want the size function to enjoy the following properties: |
d109244b89aa
tuned definition of 'size' function to get nicer properties
blanchet
parents:
58337
diff
changeset
|
166 |
|
58355
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
167 |
1. The size of a list should coincide with its length. |
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
168 |
2. All the nonrecursive constructors of a type should have the same size. |
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
169 |
3. Each constructor through which nested recursion takes place should count as at least |
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
170 |
one in the generic size function. |
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
171 |
4. The "size" function should be definable as "size_t (%_. 0) ... (%_. 0)", where "size_t" |
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
172 |
is the generic function. |
58338
d109244b89aa
tuned definition of 'size' function to get nicer properties
blanchet
parents:
58337
diff
changeset
|
173 |
|
58355
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
174 |
This explains the somewhat convoluted logic ahead. *) |
58338
d109244b89aa
tuned definition of 'size' function to get nicer properties
blanchet
parents:
58337
diff
changeset
|
175 |
|
d109244b89aa
tuned definition of 'size' function to get nicer properties
blanchet
parents:
58337
diff
changeset
|
176 |
val base_case = |
d109244b89aa
tuned definition of 'size' function to get nicer properties
blanchet
parents:
58337
diff
changeset
|
177 |
if forall (is_recursive_or_plain_case o binder_types) rec_arg_Ts then HOLogic.zero |
d109244b89aa
tuned definition of 'size' function to get nicer properties
blanchet
parents:
58337
diff
changeset
|
178 |
else HOLogic.Suc_zero; |
d109244b89aa
tuned definition of 'size' function to get nicer properties
blanchet
parents:
58337
diff
changeset
|
179 |
|
58355
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
180 |
fun mk_size_arg rec_arg_T = |
58179 | 181 |
let |
182 |
val x_Ts = binder_types rec_arg_T; |
|
183 |
val m = length x_Ts; |
|
184 |
val x_names = variant_names m "x"; |
|
185 |
val xs = map2 (curry Free) x_names x_Ts; |
|
58738 | 186 |
val (summands, size_gen_o_mapss) = |
58355
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
187 |
fold_map mk_size_of_arg xs [] |
58337 | 188 |
|>> remove (op =) HOLogic.zero; |
58179 | 189 |
val sum = |
62690 | 190 |
if null summands then base_case 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
|
191 |
in |
58738 | 192 |
append size_gen_o_mapss |
58355
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
193 |
#> pair (fold_rev Term.lambda (map substCnatT xs) sum) |
56640
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
194 |
end; |
0a35354137a5
generate 'rec_o_map' and 'size_o_map' in size extension
blanchet
parents:
56639
diff
changeset
|
195 |
|
58355
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
196 |
fun mk_size_rhs recx = |
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
197 |
fold_map mk_size_arg rec_arg_Ts |
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
198 |
#>> (fn args => fold_rev Term.lambda fs (Term.list_comb (substCnatT recx, args))); |
58179 | 199 |
|
200 |
val maybe_conceal_def_binding = Thm.def_binding |
|
62093 | 201 |
#> not (Config.get lthy0 bnf_internals) ? Binding.concealed; |
58179 | 202 |
|
58738 | 203 |
val (size_rhss, nested_size_gen_o_mapss) = fold_map mk_size_rhs recs []; |
58179 | 204 |
val size_Ts = map fastype_of size_rhss; |
205 |
||
58738 | 206 |
val nested_size_gen_o_maps_complete = forall (not o null) nested_size_gen_o_mapss; |
207 |
val nested_size_gen_o_maps = fold (union Thm.eq_thm_prop) nested_size_gen_o_mapss []; |
|
58355
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
208 |
|
61101
7b915ca69af1
use open/close_target rather than Local_Theory.restore to get polymorphic definitions;
traytel
parents:
60784
diff
changeset
|
209 |
val ((raw_size_consts, raw_size_defs), (lthy1, lthy1_old)) = lthy0 |
72450 | 210 |
|> (snd o Local_Theory.begin_nested) |
58634
9f10d82e8188
added parameterized ML antiquotations @{map N}, @{fold N}, @{fold_map N}, @{split_list N};
wenzelm
parents:
58578
diff
changeset
|
211 |
|> apfst split_list o @{fold_map 2} (fn b => fn rhs => |
58179 | 212 |
Local_Theory.define ((b, NoSyn), ((maybe_conceal_def_binding b, []), rhs)) |
213 |
#>> apsnd snd) |
|
214 |
size_bs size_rhss |
|
72450 | 215 |
||> `Local_Theory.end_nested; |
58179 | 216 |
|
61101
7b915ca69af1
use open/close_target rather than Local_Theory.restore to get polymorphic definitions;
traytel
parents:
60784
diff
changeset
|
217 |
val phi = Proof_Context.export_morphism lthy1_old lthy1; |
58179 | 218 |
|
219 |
val size_defs = map (Morphism.thm phi) raw_size_defs; |
|
220 |
||
221 |
val size_consts0 = map (Morphism.term phi) raw_size_consts; |
|
222 |
val size_consts = map2 retype_const_or_free size_Ts size_consts0; |
|
223 |
val size_constsB = map (Term.map_types B_ify) size_consts; |
|
224 |
||
225 |
val zeros = map mk_abs_zero_nat As; |
|
226 |
||
227 |
val overloaded_size_rhss = map (fn c => Term.list_comb (c, zeros)) size_consts; |
|
228 |
val overloaded_size_Ts = map fastype_of overloaded_size_rhss; |
|
69593 | 229 |
val overloaded_size_consts = map (curry Const \<^const_name>\<open>size\<close>) overloaded_size_Ts; |
58179 | 230 |
val overloaded_size_def_bs = |
231 |
map (maybe_conceal_def_binding o Binding.suffix_name "_overloaded") size_bs; |
|
232 |
||
233 |
fun define_overloaded_size def_b lhs0 rhs lthy = |
|
234 |
let |
|
235 |
val Free (c, _) = Syntax.check_term lthy lhs0; |
|
62082 | 236 |
val ((_, (_, thm)), lthy') = lthy |
237 |
|> Local_Theory.define ((Binding.name c, NoSyn), ((def_b, []), rhs)); |
|
59644 | 238 |
val thy_ctxt = Proof_Context.init_global (Proof_Context.theory_of lthy'); |
239 |
val thm' = singleton (Proof_Context.export lthy' thy_ctxt) thm; |
|
58179 | 240 |
in (thm', lthy') end; |
241 |
||
242 |
val (overloaded_size_defs, lthy2) = lthy1 |
|
243 |
|> Local_Theory.background_theory_result |
|
244 |
(Class.instantiation (T_names, map dest_TFree As, [HOLogic.class_size]) |
|
58634
9f10d82e8188
added parameterized ML antiquotations @{map N}, @{fold N}, @{fold_map N}, @{split_list N};
wenzelm
parents:
58578
diff
changeset
|
245 |
#> @{fold_map 3} define_overloaded_size overloaded_size_def_bs overloaded_size_consts |
58179 | 246 |
overloaded_size_rhss |
59498
50b60f501b05
proper context for resolve_tac, eresolve_tac, dresolve_tac, forward_tac etc.;
wenzelm
parents:
59145
diff
changeset
|
247 |
##> Class.prove_instantiation_instance (fn ctxt => Class.intro_classes_tac ctxt []) |
58179 | 248 |
##> Local_Theory.exit_global); |
56638 | 249 |
|
58179 | 250 |
val size_defs' = |
67710
cc2db3239932
added HOLogic.mk_obj_eq convenience and eliminated some clones;
wenzelm
parents:
67314
diff
changeset
|
251 |
map (mk_unabs_def (num_As + 1) o HOLogic.mk_obj_eq) size_defs; |
58179 | 252 |
val size_defs_unused_0 = |
67710
cc2db3239932
added HOLogic.mk_obj_eq convenience and eliminated some clones;
wenzelm
parents:
67314
diff
changeset
|
253 |
map (mk_unabs_def_unused_0 (num_As + 1) o HOLogic.mk_obj_eq) size_defs; |
58179 | 254 |
val overloaded_size_defs' = |
67710
cc2db3239932
added HOLogic.mk_obj_eq convenience and eliminated some clones;
wenzelm
parents:
67314
diff
changeset
|
255 |
map (mk_unabs_def 1 o HOLogic.mk_obj_eq) overloaded_size_defs; |
58179 | 256 |
|
61760 | 257 |
val nested_size_maps = |
258 |
map (mk_pointful lthy2) nested_size_gen_o_maps @ nested_size_gen_o_maps; |
|
59576
913c4afb0388
avoid duplicate simp warning for datatypes with explicit products
blanchet
parents:
59498
diff
changeset
|
259 |
val all_inj_maps = |
913c4afb0388
avoid duplicate simp warning for datatypes with explicit products
blanchet
parents:
59498
diff
changeset
|
260 |
@{thm prod.inj_map} :: map inj_map_of_bnf (fp_bnfs @ fp_nesting_bnfs @ live_nesting_bnfs) |
58179 | 261 |
|> distinct Thm.eq_thm_prop; |
262 |
||
263 |
fun derive_size_simp size_def' simp0 = |
|
264 |
(trans OF [size_def', simp0]) |
|
265 |
|> Simplifier.asm_full_simplify (ss_only (@{thms inj_on_convol_ident id_def o_def |
|
266 |
snd_conv} @ all_inj_maps @ nested_size_maps) lthy2) |
|
63222
fe92356ade42
eliminated pointless alias (no warning for duplicates);
wenzelm
parents:
63170
diff
changeset
|
267 |
|> Local_Defs.fold lthy2 size_defs_unused_0; |
58179 | 268 |
|
269 |
fun derive_overloaded_size_simp overloaded_size_def' simp0 = |
|
270 |
(trans OF [overloaded_size_def', simp0]) |
|
271 |
|> unfold_thms lthy2 @{thms add_0_left add_0_right} |
|
63222
fe92356ade42
eliminated pointless alias (no warning for duplicates);
wenzelm
parents:
63170
diff
changeset
|
272 |
|> Local_Defs.fold lthy2 (overloaded_size_defs @ all_overloaded_size_defs_of lthy2); |
58179 | 273 |
|
274 |
val size_simpss = map2 (map o derive_size_simp) size_defs' rec_thmss; |
|
275 |
val size_simps = flat size_simpss; |
|
276 |
val overloaded_size_simpss = |
|
277 |
map2 (map o derive_overloaded_size_simp) overloaded_size_defs' size_simpss; |
|
62082 | 278 |
val overloaded_size_simps = flat overloaded_size_simpss; |
58179 | 279 |
val size_thmss = map2 append size_simpss overloaded_size_simpss; |
66494 | 280 |
val size_gen_thmss = size_simpss; |
281 |
||
58913 | 282 |
fun rhs_is_zero thm = |
59582 | 283 |
let val Const (trueprop, _) $ (Const (eq, _) $ _ $ rhs) = Thm.prop_of thm in |
69593 | 284 |
trueprop = \<^const_name>\<open>Trueprop\<close> andalso eq = \<^const_name>\<open>HOL.eq\<close> andalso |
58913 | 285 |
rhs = HOLogic.zero |
286 |
end; |
|
287 |
||
288 |
val size_neq_thmss = @{map 3} (fn fp_sugar => fn size => fn size_thms => |
|
62082 | 289 |
if exists rhs_is_zero size_thms then |
290 |
[] |
|
58913 | 291 |
else |
292 |
let |
|
61334
8d40ddaa427f
collect the names from goals in favor of fragile exports
traytel
parents:
61101
diff
changeset
|
293 |
val (xs, _) = mk_Frees "x" (binder_types (fastype_of size)) lthy2; |
58913 | 294 |
val goal = |
295 |
HOLogic.mk_Trueprop (BNF_LFP_Util.mk_not_eq (list_comb (size, xs)) HOLogic.zero); |
|
61334
8d40ddaa427f
collect the names from goals in favor of fragile exports
traytel
parents:
61101
diff
changeset
|
296 |
val vars = Variable.add_free_names lthy2 goal []; |
58913 | 297 |
val thm = |
61334
8d40ddaa427f
collect the names from goals in favor of fragile exports
traytel
parents:
61101
diff
changeset
|
298 |
Goal.prove_sorry lthy2 vars [] goal (fn {context = ctxt, ...} => |
59621
291934bac95e
Thm.cterm_of and Thm.ctyp_of operate on local context;
wenzelm
parents:
59582
diff
changeset
|
299 |
mk_size_neq ctxt (map (Thm.cterm_of lthy2) xs) |
58913 | 300 |
(#exhaust (#ctr_sugar (#fp_ctr_sugar fp_sugar))) size_thms) |
301 |
|> single |
|
70494 | 302 |
|> map (Thm.close_derivation \<^here>); |
62082 | 303 |
in thm end) fp_sugars overloaded_size_consts overloaded_size_simpss; |
58179 | 304 |
|
305 |
val ABs = As ~~ Bs; |
|
306 |
val g_names = variant_names num_As "g"; |
|
307 |
val gs = map2 (curry Free) g_names (map (op -->) ABs); |
|
308 |
||
309 |
val liveness = map (op <>) ABs; |
|
310 |
val live_gs = AList.find (op =) (gs ~~ liveness) true; |
|
311 |
val live = length live_gs; |
|
312 |
||
313 |
val maps0 = map map_of_bnf fp_bnfs; |
|
314 |
||
58738 | 315 |
val size_gen_o_map_thmss = |
62690 | 316 |
if live = 0 then |
317 |
replicate nn [] |
|
58179 | 318 |
else |
319 |
let |
|
320 |
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
|
321 |
|
58738 | 322 |
val size_gen_o_map_conds = |
323 |
if exists (can Logic.dest_implies o Thm.prop_of) nested_size_gen_o_maps then |
|
58179 | 324 |
map (HOLogic.mk_Trueprop o mk_inj) live_gs |
325 |
else |
|
326 |
[]; |
|
327 |
||
328 |
val fsizes = map (fn size_constB => Term.list_comb (size_constB, fsB)) size_constsB; |
|
58738 | 329 |
val size_gen_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
|
330 |
|
58179 | 331 |
val fgs = map2 (fn fB => fn g as Free (_, Type (_, [A, B])) => |
332 |
if A = B then fB else HOLogic.mk_comp (fB, g)) fsB gs; |
|
58738 | 333 |
val size_gen_o_map_rhss = map (fn c => Term.list_comb (c, fgs)) size_consts; |
58179 | 334 |
|
58738 | 335 |
val size_gen_o_map_goals = |
58179 | 336 |
map2 (fold_rev (fold_rev Logic.all) [fsB, gs] o |
58738 | 337 |
curry Logic.list_implies size_gen_o_map_conds o HOLogic.mk_Trueprop oo |
338 |
curry HOLogic.mk_eq) size_gen_o_map_lhss size_gen_o_map_rhss; |
|
58179 | 339 |
|
58734 | 340 |
val rec_o_maps = |
63859
dca6fabd8060
make (co)induct component of 'fp_sugar' optional, for the benefit of nonuniform (co)datatypes and other similar extensions
blanchet
parents:
63239
diff
changeset
|
341 |
fold_rev (curry (op @) o #co_rec_o_maps o the o #fp_co_induct_sugar) fp_sugars []; |
58732 | 342 |
|
58738 | 343 |
val size_gen_o_map_thmss = |
64532
fc2835a932d9
don't generate 'size_gen_o_map' property if its type variable is too limited anyway to be useful
blanchet
parents:
63859
diff
changeset
|
344 |
if nested_size_gen_o_maps_complete |
69593 | 345 |
andalso forall (fn TFree (_, S) => S = \<^sort>\<open>type\<close>) As then |
58634
9f10d82e8188
added parameterized ML antiquotations @{map N}, @{fold N}, @{fold_map N}, @{split_list N};
wenzelm
parents:
58578
diff
changeset
|
346 |
@{map 3} (fn goal => fn size_def => fn rec_o_map => |
58355
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
347 |
Goal.prove_sorry lthy2 [] [] goal (fn {context = ctxt, ...} => |
58738 | 348 |
mk_size_gen_o_map_tac ctxt size_def rec_o_map all_inj_maps nested_size_maps) |
70494 | 349 |
|> Thm.close_derivation \<^here> |
58355
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
350 |
|> single) |
58738 | 351 |
size_gen_o_map_goals size_defs rec_o_maps |
58355
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
352 |
else |
9a041a55ee95
syntactic check to determine when to prove 'nested_size_o_map'
blanchet
parents:
58353
diff
changeset
|
353 |
replicate nn []; |
58179 | 354 |
in |
58738 | 355 |
size_gen_o_map_thmss |
58179 | 356 |
end; |
357 |
||
358 |
val massage_multi_notes = |
|
359 |
maps (fn (thmN, thmss, attrs) => |
|
360 |
map2 (fn T_name => fn thms => |
|
361 |
((Binding.qualify true (Long_Name.base_name T_name) (Binding.name thmN), attrs), |
|
362 |
[(thms, [])])) |
|
363 |
T_names thmss) |
|
364 |
#> filter_out (null o fst o hd o snd); |
|
365 |
||
366 |
val notes = |
|
66251
cd935b7cb3fb
proper concept of code declaration wrt. atomicity and Isar declarations
haftmann
parents:
64532
diff
changeset
|
367 |
[(sizeN, size_thmss, nitpicksimp_attrs @ simp_attrs), |
58736 | 368 |
(size_genN, size_gen_thmss, []), |
58913 | 369 |
(size_gen_o_mapN, size_gen_o_map_thmss, []), |
370 |
(size_neqN, size_neq_thmss, [])] |
|
58179 | 371 |
|> massage_multi_notes; |
372 |
||
373 |
val (noted, lthy3) = |
|
374 |
lthy2 |
|
71214
5727bcc3c47c
proper spec_rule name via naming/binding/Morphism.binding;
wenzelm
parents:
71179
diff
changeset
|
375 |
|> Spec_Rules.add Binding.empty Spec_Rules.equational size_consts size_simps |
5727bcc3c47c
proper spec_rule name via naming/binding/Morphism.binding;
wenzelm
parents:
71179
diff
changeset
|
376 |
|> Spec_Rules.add Binding.empty Spec_Rules.equational |
5727bcc3c47c
proper spec_rule name via naming/binding/Morphism.binding;
wenzelm
parents:
71179
diff
changeset
|
377 |
overloaded_size_consts overloaded_size_simps |
66251
cd935b7cb3fb
proper concept of code declaration wrt. atomicity and Isar declarations
haftmann
parents:
64532
diff
changeset
|
378 |
|> Code.declare_default_eqns (map (rpair true) (flat size_thmss)) |
67314 | 379 |
(*Ideally, this would be issued only if the "code" plugin is enabled.*) |
58179 | 380 |
|> Local_Theory.notes notes; |
381 |
||
382 |
val phi0 = substitute_noted_thm noted; |
|
383 |
in |
|
384 |
lthy3 |
|
78095 | 385 |
|> Local_Theory.declaration {syntax = false, pervasive = true, pos = \<^here>} |
62082 | 386 |
(fn phi => Data.map (@{fold 3} (fn T_name => fn Const (size_name, _) => |
387 |
fn overloaded_size_def => |
|
388 |
let val morph = Morphism.thm (phi0 $> phi) in |
|
67314 | 389 |
Symtab.update (T_name, (size_name, (morph overloaded_size_def, |
390 |
map morph overloaded_size_simps, maps (map morph) size_gen_o_map_thmss))) |
|
62082 | 391 |
end) |
392 |
T_names size_consts overloaded_size_defs)) |
|
58179 | 393 |
end |
394 |
| generate_datatype_size _ lthy = lthy; |
|
395 |
||
69593 | 396 |
val size_plugin = Plugin_Name.declare_setup \<^binding>\<open>size\<close>; |
58659
6c9821c32dd5
Local_Interpretation is superseded by Plugin with formal Plugin_Name management, avoiding undeclared strings;
wenzelm
parents:
58634
diff
changeset
|
397 |
val _ = Theory.setup (fp_sugars_interpretation size_plugin generate_datatype_size); |
56638 | 398 |
|
399 |
end; |