82 unfold_thms_tac ctxt [size_def] THEN |
82 unfold_thms_tac ctxt [size_def] THEN |
83 HEADGOAL (rtac (rec_o_map RS trans) THEN' |
83 HEADGOAL (rtac (rec_o_map RS trans) THEN' |
84 asm_simp_tac (ss_only (inj_maps @ size_maps @ size_o_map_simp_thms) ctxt)) THEN |
84 asm_simp_tac (ss_only (inj_maps @ size_maps @ size_o_map_simp_thms) ctxt)) THEN |
85 IF_UNSOLVED (unfold_thms_tac ctxt @{thms o_def} THEN HEADGOAL (rtac refl)); |
85 IF_UNSOLVED (unfold_thms_tac ctxt @{thms o_def} THEN HEADGOAL (rtac refl)); |
86 |
86 |
87 fun generate_lfp_size (fp_sugars as ({T = Type (_, As), BT = Type (_, Bs), |
87 fun generate_datatype_size (fp_sugars as ({T = Type (_, As), BT = Type (_, Bs), fp = Least_FP, |
88 fp_res = {bnfs = fp_bnfs, xtor_co_rec_o_map_thms = ctor_rec_o_maps, ...}, fp_nesting_bnfs, |
88 fp_res = {bnfs = fp_bnfs, xtor_co_rec_o_map_thms = ctor_rec_o_maps, ...}, fp_nesting_bnfs, |
89 live_nesting_bnfs, ...} : fp_sugar) :: _) lthy0 = |
89 live_nesting_bnfs, ...} : fp_sugar) :: _) lthy0 = |
90 let |
90 let |
91 val data = Data.get (Context.Proof lthy0); |
91 val data = Data.get (Context.Proof lthy0); |
92 |
92 |
93 val Ts = map #T fp_sugars |
93 val Ts = map #T fp_sugars |
94 val T_names = map (fst o dest_Type) Ts; |
94 val T_names = map (fst o dest_Type) Ts; |
95 val nn = length Ts; |
95 val nn = length Ts; |
96 |
96 |
97 val B_ify = Term.typ_subst_atomic (As ~~ Bs); |
97 val B_ify = Term.typ_subst_atomic (As ~~ Bs); |
98 |
98 |
99 val recs = map #co_rec fp_sugars; |
99 val recs = map #co_rec fp_sugars; |
100 val rec_thmss = map #co_rec_thms fp_sugars; |
100 val rec_thmss = map #co_rec_thms fp_sugars; |
101 val rec_Ts as rec_T1 :: _ = map fastype_of recs; |
101 val rec_Ts as rec_T1 :: _ = map fastype_of recs; |
102 val rec_arg_Ts = binder_fun_types rec_T1; |
102 val rec_arg_Ts = binder_fun_types rec_T1; |
103 val Cs = map body_type rec_Ts; |
103 val Cs = map body_type rec_Ts; |
104 val Cs_rho = map (rpair HOLogic.natT) Cs; |
104 val Cs_rho = map (rpair HOLogic.natT) Cs; |
105 val substCnatT = Term.subst_atomic_types Cs_rho; |
105 val substCnatT = Term.subst_atomic_types Cs_rho; |
106 |
106 |
107 val f_Ts = map mk_to_natT As; |
107 val f_Ts = map mk_to_natT As; |
108 val f_TsB = map mk_to_natT Bs; |
108 val f_TsB = map mk_to_natT Bs; |
109 val num_As = length As; |
109 val num_As = length As; |
110 |
110 |
111 fun variant_names n pre = fst (Variable.variant_fixes (replicate n pre) lthy0); |
111 fun variant_names n pre = fst (Variable.variant_fixes (replicate n pre) lthy0); |
112 |
112 |
113 val f_names = variant_names num_As "f"; |
113 val f_names = variant_names num_As "f"; |
114 val fs = map2 (curry Free) f_names f_Ts; |
114 val fs = map2 (curry Free) f_names f_Ts; |
115 val fsB = map2 (curry Free) f_names f_TsB; |
115 val fsB = map2 (curry Free) f_names f_TsB; |
116 val As_fs = As ~~ fs; |
116 val As_fs = As ~~ fs; |
117 |
117 |
118 val size_bs = |
118 val size_bs = |
119 map ((fn base => Binding.qualify false base (Binding.name (prefix size_N base))) o |
119 map ((fn base => Binding.qualify false base (Binding.name (prefix size_N base))) o |
120 Long_Name.base_name) T_names; |
120 Long_Name.base_name) T_names; |
121 |
121 |
122 fun is_pair_C @{type_name prod} [_, T'] = member (op =) Cs T' |
122 fun is_pair_C @{type_name prod} [_, T'] = member (op =) Cs T' |
123 | is_pair_C _ _ = false; |
123 | is_pair_C _ _ = false; |
124 |
124 |
125 fun mk_size_of_typ (T as TFree _) = |
125 fun mk_size_of_typ (T as TFree _) = |
126 pair (case AList.lookup (op =) As_fs T of |
126 pair (case AList.lookup (op =) As_fs T of |
127 SOME f => f |
127 SOME f => f |
128 | NONE => if member (op =) Cs T then Term.absdummy T (Bound 0) else mk_abs_zero_nat T) |
128 | NONE => if member (op =) Cs T then Term.absdummy T (Bound 0) else mk_abs_zero_nat T) |
129 | mk_size_of_typ (T as Type (s, Ts)) = |
129 | mk_size_of_typ (T as Type (s, Ts)) = |
130 if is_pair_C s Ts then |
130 if is_pair_C s Ts then |
131 pair (snd_const T) |
131 pair (snd_const T) |
132 else if exists (exists_subtype_in (As @ Cs)) Ts then |
132 else if exists (exists_subtype_in (As @ Cs)) Ts then |
133 (case Symtab.lookup data s of |
133 (case Symtab.lookup data s of |
134 SOME (size_name, (_, size_o_maps)) => |
134 SOME (size_name, (_, size_o_maps)) => |
135 let |
135 let |
136 val (args, size_o_mapss') = split_list (map (fn T => mk_size_of_typ T []) Ts); |
136 val (args, size_o_mapss') = split_list (map (fn T => mk_size_of_typ T []) Ts); |
137 val size_const = Const (size_name, map fastype_of args ---> mk_to_natT T); |
137 val size_const = Const (size_name, map fastype_of args ---> mk_to_natT T); |
138 in |
138 in |
139 fold (union Thm.eq_thm_prop) (size_o_maps :: size_o_mapss') |
139 fold (union Thm.eq_thm_prop) (size_o_maps :: size_o_mapss') |
140 #> pair (Term.list_comb (size_const, args)) |
140 #> pair (Term.list_comb (size_const, args)) |
141 end |
141 end |
142 | _ => pair (mk_abs_zero_nat T)) |
142 | _ => pair (mk_abs_zero_nat T)) |
|
143 else |
|
144 pair (mk_abs_zero_nat T); |
|
145 |
|
146 fun mk_size_of_arg t = |
|
147 mk_size_of_typ (fastype_of t) #>> (fn s => substCnatT (betapply (s, t))); |
|
148 |
|
149 fun mk_size_arg rec_arg_T size_o_maps = |
|
150 let |
|
151 val x_Ts = binder_types rec_arg_T; |
|
152 val m = length x_Ts; |
|
153 val x_names = variant_names m "x"; |
|
154 val xs = map2 (curry Free) x_names x_Ts; |
|
155 val (summands, size_o_maps') = |
|
156 fold_map mk_size_of_arg xs size_o_maps |
|
157 |>> remove (op =) zero_nat; |
|
158 val sum = |
|
159 if null summands then HOLogic.zero |
|
160 else foldl1 mk_plus_nat (summands @ [HOLogic.Suc_zero]); |
|
161 in |
|
162 (fold_rev Term.lambda (map substCnatT xs) sum, size_o_maps') |
|
163 end; |
|
164 |
|
165 fun mk_size_rhs recx size_o_maps = |
|
166 fold_map mk_size_arg rec_arg_Ts size_o_maps |
|
167 |>> (fn args => fold_rev Term.lambda fs (Term.list_comb (substCnatT recx, args))); |
|
168 |
|
169 val maybe_conceal_def_binding = Thm.def_binding |
|
170 #> Config.get lthy0 bnf_note_all = false ? Binding.conceal; |
|
171 |
|
172 val (size_rhss, nested_size_o_maps) = fold_map mk_size_rhs recs []; |
|
173 val size_Ts = map fastype_of size_rhss; |
|
174 |
|
175 val ((raw_size_consts, raw_size_defs), (lthy1', lthy1)) = lthy0 |
|
176 |> apfst split_list o fold_map2 (fn b => fn rhs => |
|
177 Local_Theory.define ((b, NoSyn), ((maybe_conceal_def_binding b, []), rhs)) |
|
178 #>> apsnd snd) |
|
179 size_bs size_rhss |
|
180 ||> `Local_Theory.restore; |
|
181 |
|
182 val phi = Proof_Context.export_morphism lthy1 lthy1'; |
|
183 |
|
184 val size_defs = map (Morphism.thm phi) raw_size_defs; |
|
185 |
|
186 val size_consts0 = map (Morphism.term phi) raw_size_consts; |
|
187 val size_consts = map2 retype_const_or_free size_Ts size_consts0; |
|
188 val size_constsB = map (Term.map_types B_ify) size_consts; |
|
189 |
|
190 val zeros = map mk_abs_zero_nat As; |
|
191 |
|
192 val overloaded_size_rhss = map (fn c => Term.list_comb (c, zeros)) size_consts; |
|
193 val overloaded_size_Ts = map fastype_of overloaded_size_rhss; |
|
194 val overloaded_size_consts = map (curry Const @{const_name size}) overloaded_size_Ts; |
|
195 val overloaded_size_def_bs = |
|
196 map (maybe_conceal_def_binding o Binding.suffix_name "_overloaded") size_bs; |
|
197 |
|
198 fun define_overloaded_size def_b lhs0 rhs lthy = |
|
199 let |
|
200 val Free (c, _) = Syntax.check_term lthy lhs0; |
|
201 val (thm, lthy') = lthy |
|
202 |> Local_Theory.define ((Binding.name c, NoSyn), ((def_b, []), rhs)) |
|
203 |-> (fn (t, (_, thm)) => Spec_Rules.add Spec_Rules.Equational ([t], [thm]) #> pair thm); |
|
204 val ctxt_thy = Proof_Context.init_global (Proof_Context.theory_of lthy'); |
|
205 val thm' = singleton (Proof_Context.export lthy' ctxt_thy) thm; |
|
206 in (thm', lthy') end; |
|
207 |
|
208 val (overloaded_size_defs, lthy2) = lthy1 |
|
209 |> Local_Theory.background_theory_result |
|
210 (Class.instantiation (T_names, map dest_TFree As, [HOLogic.class_size]) |
|
211 #> fold_map3 define_overloaded_size overloaded_size_def_bs overloaded_size_consts |
|
212 overloaded_size_rhss |
|
213 ##> Class.prove_instantiation_instance (K (Class.intro_classes_tac [])) |
|
214 ##> Local_Theory.exit_global); |
|
215 |
|
216 val size_defs' = |
|
217 map (mk_unabs_def (num_As + 1) o (fn thm => thm RS meta_eq_to_obj_eq)) size_defs; |
|
218 val size_defs_unused_0 = |
|
219 map (mk_unabs_def_unused_0 (num_As + 1) o (fn thm => thm RS meta_eq_to_obj_eq)) size_defs; |
|
220 val overloaded_size_defs' = |
|
221 map (mk_unabs_def 1 o (fn thm => thm RS meta_eq_to_obj_eq)) overloaded_size_defs; |
|
222 |
|
223 val all_overloaded_size_defs = overloaded_size_defs @ |
|
224 (Spec_Rules.retrieve lthy0 @{const size ('a)} |
|
225 |> map_filter (try (fn (Spec_Rules.Equational, (_, [thm])) => thm))); |
|
226 |
|
227 val nested_size_maps = map (pointfill lthy2) nested_size_o_maps @ nested_size_o_maps; |
|
228 val all_inj_maps = map inj_map_of_bnf (fp_bnfs @ fp_nesting_bnfs @ live_nesting_bnfs) |
|
229 |> distinct Thm.eq_thm_prop; |
|
230 |
|
231 fun derive_size_simp size_def' simp0 = |
|
232 (trans OF [size_def', simp0]) |
|
233 |> Simplifier.asm_full_simplify (ss_only (@{thms inj_on_convol_ident id_def o_def |
|
234 snd_conv} @ all_inj_maps @ nested_size_maps) lthy2) |
|
235 |> fold_thms lthy2 size_defs_unused_0; |
|
236 |
|
237 fun derive_overloaded_size_simp overloaded_size_def' simp0 = |
|
238 (trans OF [overloaded_size_def', simp0]) |
|
239 |> unfold_thms lthy2 @{thms add_0_left add_0_right} |
|
240 |> fold_thms lthy2 all_overloaded_size_defs; |
|
241 |
|
242 val size_simpss = map2 (map o derive_size_simp) size_defs' rec_thmss; |
|
243 val size_simps = flat size_simpss; |
|
244 val overloaded_size_simpss = |
|
245 map2 (map o derive_overloaded_size_simp) overloaded_size_defs' size_simpss; |
|
246 val size_thmss = map2 append size_simpss overloaded_size_simpss; |
|
247 |
|
248 val ABs = As ~~ Bs; |
|
249 val g_names = variant_names num_As "g"; |
|
250 val gs = map2 (curry Free) g_names (map (op -->) ABs); |
|
251 |
|
252 val liveness = map (op <>) ABs; |
|
253 val live_gs = AList.find (op =) (gs ~~ liveness) true; |
|
254 val live = length live_gs; |
|
255 |
|
256 val maps0 = map map_of_bnf fp_bnfs; |
|
257 |
|
258 val (rec_o_map_thmss, size_o_map_thmss) = |
|
259 if live = 0 then |
|
260 `I (replicate nn []) |
143 else |
261 else |
144 pair (mk_abs_zero_nat T); |
262 let |
145 |
263 val pre_bnfs = map #pre_bnf fp_sugars; |
146 fun mk_size_of_arg t = |
264 val pre_map_defs = map map_def_of_bnf pre_bnfs; |
147 mk_size_of_typ (fastype_of t) #>> (fn s => substCnatT (betapply (s, t))); |
265 val live_nesting_map_ident0s = map map_ident0_of_bnf live_nesting_bnfs; |
148 |
266 val abs_inverses = map (#abs_inverse o #absT_info) fp_sugars; |
149 fun mk_size_arg rec_arg_T size_o_maps = |
267 val rec_defs = map #co_rec_def fp_sugars; |
150 let |
268 |
151 val x_Ts = binder_types rec_arg_T; |
269 val gmaps = map (fn map0 => Term.list_comb (mk_map live As Bs map0, live_gs)) maps0; |
152 val m = length x_Ts; |
270 |
153 val x_names = variant_names m "x"; |
271 val num_rec_args = length rec_arg_Ts; |
154 val xs = map2 (curry Free) x_names x_Ts; |
272 val h_Ts = map B_ify rec_arg_Ts; |
155 val (summands, size_o_maps') = |
273 val h_names = variant_names num_rec_args "h"; |
156 fold_map mk_size_of_arg xs size_o_maps |
274 val hs = map2 (curry Free) h_names h_Ts; |
157 |>> remove (op =) zero_nat; |
275 val hrecs = map (fn recx => Term.list_comb (Term.map_types B_ify recx, hs)) recs; |
158 val sum = |
276 |
159 if null summands then HOLogic.zero |
277 val rec_o_map_lhss = map2 (curry HOLogic.mk_comp) hrecs gmaps; |
160 else foldl1 mk_plus_nat (summands @ [HOLogic.Suc_zero]); |
278 |
161 in |
279 val ABgs = ABs ~~ gs; |
162 (fold_rev Term.lambda (map substCnatT xs) sum, size_o_maps') |
280 |
163 end; |
281 fun mk_rec_arg_arg (x as Free (_, T)) = |
164 |
282 let val U = B_ify T in |
165 fun mk_size_rhs recx size_o_maps = |
283 if T = U then x else build_map lthy2 [] (the o AList.lookup (op =) ABgs) (T, U) $ x |
166 fold_map mk_size_arg rec_arg_Ts size_o_maps |
284 end; |
167 |>> (fn args => fold_rev Term.lambda fs (Term.list_comb (substCnatT recx, args))); |
285 |
168 |
286 fun mk_rec_o_map_arg rec_arg_T h = |
169 val maybe_conceal_def_binding = Thm.def_binding |
287 let |
170 #> Config.get lthy0 bnf_note_all = false ? Binding.conceal; |
288 val x_Ts = binder_types rec_arg_T; |
171 |
289 val m = length x_Ts; |
172 val (size_rhss, nested_size_o_maps) = fold_map mk_size_rhs recs []; |
290 val x_names = variant_names m "x"; |
173 val size_Ts = map fastype_of size_rhss; |
291 val xs = map2 (curry Free) x_names x_Ts; |
174 |
292 val xs' = map mk_rec_arg_arg xs; |
175 val ((raw_size_consts, raw_size_defs), (lthy1', lthy1)) = lthy0 |
293 in |
176 |> apfst split_list o fold_map2 (fn b => fn rhs => |
294 fold_rev Term.lambda xs (Term.list_comb (h, xs')) |
177 Local_Theory.define ((b, NoSyn), ((maybe_conceal_def_binding b, []), rhs)) #>> apsnd snd) |
295 end; |
178 size_bs size_rhss |
296 |
179 ||> `Local_Theory.restore; |
297 fun mk_rec_o_map_rhs recx = |
180 |
298 let val args = map2 mk_rec_o_map_arg rec_arg_Ts hs in |
181 val phi = Proof_Context.export_morphism lthy1 lthy1'; |
299 Term.list_comb (recx, args) |
182 |
300 end; |
183 val size_defs = map (Morphism.thm phi) raw_size_defs; |
301 |
184 |
302 val rec_o_map_rhss = map mk_rec_o_map_rhs recs; |
185 val size_consts0 = map (Morphism.term phi) raw_size_consts; |
303 |
186 val size_consts = map2 retype_const_or_free size_Ts size_consts0; |
304 val rec_o_map_goals = |
187 val size_constsB = map (Term.map_types B_ify) size_consts; |
305 map2 (fold_rev (fold_rev Logic.all) [gs, hs] o HOLogic.mk_Trueprop oo |
188 |
306 curry HOLogic.mk_eq) rec_o_map_lhss rec_o_map_rhss; |
189 val zeros = map mk_abs_zero_nat As; |
307 val rec_o_map_thms = |
190 |
308 map3 (fn goal => fn rec_def => fn ctor_rec_o_map => |
191 val overloaded_size_rhss = map (fn c => Term.list_comb (c, zeros)) size_consts; |
309 Goal.prove_sorry lthy2 [] [] goal (fn {context = ctxt, ...} => |
192 val overloaded_size_Ts = map fastype_of overloaded_size_rhss; |
310 mk_rec_o_map_tac ctxt rec_def pre_map_defs live_nesting_map_ident0s abs_inverses |
193 val overloaded_size_consts = map (curry Const @{const_name size}) overloaded_size_Ts; |
311 ctor_rec_o_map) |
194 val overloaded_size_def_bs = |
312 |> Thm.close_derivation) |
195 map (maybe_conceal_def_binding o Binding.suffix_name "_overloaded") size_bs; |
313 rec_o_map_goals rec_defs ctor_rec_o_maps; |
196 |
314 |
197 fun define_overloaded_size def_b lhs0 rhs lthy = |
315 val size_o_map_conds = |
198 let |
316 if exists (can Logic.dest_implies o Thm.prop_of) nested_size_o_maps then |
199 val Free (c, _) = Syntax.check_term lthy lhs0; |
317 map (HOLogic.mk_Trueprop o mk_inj) live_gs |
200 val (thm, lthy') = lthy |
318 else |
201 |> Local_Theory.define ((Binding.name c, NoSyn), ((def_b, []), rhs)) |
319 []; |
202 |-> (fn (t, (_, thm)) => Spec_Rules.add Spec_Rules.Equational ([t], [thm]) #> pair thm); |
320 |
203 val ctxt_thy = Proof_Context.init_global (Proof_Context.theory_of lthy'); |
321 val fsizes = map (fn size_constB => Term.list_comb (size_constB, fsB)) size_constsB; |
204 val thm' = singleton (Proof_Context.export lthy' ctxt_thy) thm; |
322 val size_o_map_lhss = map2 (curry HOLogic.mk_comp) fsizes gmaps; |
205 in (thm', lthy') end; |
323 |
206 |
324 val fgs = map2 (fn fB => fn g as Free (_, Type (_, [A, B])) => |
207 val (overloaded_size_defs, lthy2) = lthy1 |
325 if A = B then fB else HOLogic.mk_comp (fB, g)) fsB gs; |
208 |> Local_Theory.background_theory_result |
326 val size_o_map_rhss = map (fn c => Term.list_comb (c, fgs)) size_consts; |
209 (Class.instantiation (T_names, map dest_TFree As, [HOLogic.class_size]) |
327 |
210 #> fold_map3 define_overloaded_size overloaded_size_def_bs overloaded_size_consts |
328 val size_o_map_goals = |
211 overloaded_size_rhss |
329 map2 (fold_rev (fold_rev Logic.all) [fsB, gs] o |
212 ##> Class.prove_instantiation_instance (K (Class.intro_classes_tac [])) |
330 curry Logic.list_implies size_o_map_conds o HOLogic.mk_Trueprop oo |
213 ##> Local_Theory.exit_global); |
331 curry HOLogic.mk_eq) size_o_map_lhss size_o_map_rhss; |
214 |
332 |
215 val size_defs' = |
333 (* The "size o map" theorem generation will fail if "nested_size_maps" is incomplete, |
216 map (mk_unabs_def (num_As + 1) o (fn thm => thm RS meta_eq_to_obj_eq)) size_defs; |
334 which occurs when there is recursion through non-datatypes. In this case, we simply |
217 val size_defs_unused_0 = |
335 avoid generating the theorem. The resulting characteristic lemmas are then expressed |
218 map (mk_unabs_def_unused_0 (num_As + 1) o (fn thm => thm RS meta_eq_to_obj_eq)) size_defs; |
336 in terms of "map", which is not the end of the world. *) |
219 val overloaded_size_defs' = |
337 val size_o_map_thmss = |
220 map (mk_unabs_def 1 o (fn thm => thm RS meta_eq_to_obj_eq)) overloaded_size_defs; |
338 map3 (fn goal => fn size_def => the_list o try (fn rec_o_map => |
221 |
339 Goal.prove (*no sorry*) lthy2 [] [] goal (fn {context = ctxt, ...} => |
222 val all_overloaded_size_defs = overloaded_size_defs @ |
340 mk_size_o_map_tac ctxt size_def rec_o_map all_inj_maps nested_size_maps) |
223 (Spec_Rules.retrieve lthy0 @{const size ('a)} |
341 |> Thm.close_derivation)) |
224 |> map_filter (try (fn (Spec_Rules.Equational, (_, [thm])) => thm))); |
342 size_o_map_goals size_defs rec_o_map_thms |
225 |
343 in |
226 val nested_size_maps = map (pointfill lthy2) nested_size_o_maps @ nested_size_o_maps; |
344 (map single rec_o_map_thms, size_o_map_thmss) |
227 val all_inj_maps = map inj_map_of_bnf (fp_bnfs @ fp_nesting_bnfs @ live_nesting_bnfs) |
345 end; |
228 |> distinct Thm.eq_thm_prop; |
346 |
229 |
347 val massage_multi_notes = |
230 fun derive_size_simp size_def' simp0 = |
348 maps (fn (thmN, thmss, attrs) => |
231 (trans OF [size_def', simp0]) |
349 map2 (fn T_name => fn thms => |
232 |> Simplifier.asm_full_simplify (ss_only (@{thms inj_on_convol_ident id_def o_def snd_conv} @ |
350 ((Binding.qualify true (Long_Name.base_name T_name) (Binding.name thmN), attrs), |
233 all_inj_maps @ nested_size_maps) lthy2) |
351 [(thms, [])])) |
234 |> fold_thms lthy2 size_defs_unused_0; |
352 T_names thmss) |
235 |
353 #> filter_out (null o fst o hd o snd); |
236 fun derive_overloaded_size_simp overloaded_size_def' simp0 = |
354 |
237 (trans OF [overloaded_size_def', simp0]) |
355 val notes = |
238 |> unfold_thms lthy2 @{thms add_0_left add_0_right} |
356 [(rec_o_mapN, rec_o_map_thmss, []), |
239 |> fold_thms lthy2 all_overloaded_size_defs; |
357 (sizeN, size_thmss, code_nitpicksimp_simp_attrs), |
240 |
358 (size_o_mapN, size_o_map_thmss, [])] |
241 val size_simpss = map2 (map o derive_size_simp) size_defs' rec_thmss; |
359 |> massage_multi_notes; |
242 val size_simps = flat size_simpss; |
360 |
243 val overloaded_size_simpss = |
361 val (noted, lthy3) = |
244 map2 (map o derive_overloaded_size_simp) overloaded_size_defs' size_simpss; |
362 lthy2 |
245 val size_thmss = map2 append size_simpss overloaded_size_simpss; |
363 |> Spec_Rules.add Spec_Rules.Equational (size_consts, size_simps) |
246 |
364 |> Local_Theory.notes notes; |
247 val ABs = As ~~ Bs; |
365 |
248 val g_names = variant_names num_As "g"; |
366 val phi0 = substitute_noted_thm noted; |
249 val gs = map2 (curry Free) g_names (map (op -->) ABs); |
367 in |
250 |
368 lthy3 |
251 val liveness = map (op <>) ABs; |
369 |> Local_Theory.declaration {syntax = false, pervasive = true} |
252 val live_gs = AList.find (op =) (gs ~~ liveness) true; |
370 (fn phi => Data.map (fold2 (fn T_name => fn Const (size_name, _) => |
253 val live = length live_gs; |
371 Symtab.update (T_name, (size_name, |
254 |
372 pairself (map (Morphism.thm (phi0 $> phi))) (size_simps, flat size_o_map_thmss)))) |
255 val maps0 = map map_of_bnf fp_bnfs; |
373 T_names size_consts)) |
256 |
374 end |
257 val (rec_o_map_thmss, size_o_map_thmss) = |
375 | generate_datatype_size _ lthy = lthy; |
258 if live = 0 then |
376 |
259 `I (replicate nn []) |
377 val _ = Theory.setup (fp_sugar_interpretation (map_local_theory o generate_datatype_size) |
260 else |
378 generate_datatype_size); |
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; |
|
269 |
|
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; |
|
322 |
|
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 |
|
346 val massage_multi_notes = |
|
347 maps (fn (thmN, thmss, attrs) => |
|
348 map2 (fn T_name => fn thms => |
|
349 ((Binding.qualify true (Long_Name.base_name T_name) (Binding.name thmN), attrs), |
|
350 [(thms, [])])) |
|
351 T_names thmss) |
|
352 #> filter_out (null o fst o hd o snd); |
|
353 |
|
354 val notes = |
|
355 [(rec_o_mapN, rec_o_map_thmss, []), |
|
356 (sizeN, size_thmss, code_nitpicksimp_simp_attrs), |
|
357 (size_o_mapN, size_o_map_thmss, [])] |
|
358 |> massage_multi_notes; |
|
359 |
|
360 val (noted, lthy3) = |
|
361 lthy2 |
|
362 |> Spec_Rules.add Spec_Rules.Equational (size_consts, size_simps) |
|
363 |> Local_Theory.notes notes; |
|
364 |
|
365 val phi0 = substitute_noted_thm noted; |
|
366 in |
|
367 lthy3 |
|
368 |> Local_Theory.declaration {syntax = false, pervasive = true} |
|
369 (fn phi => Data.map (fold2 (fn T_name => fn Const (size_name, _) => |
|
370 Symtab.update (T_name, (size_name, |
|
371 pairself (map (Morphism.thm (phi0 $> phi))) (size_simps, flat size_o_map_thmss)))) |
|
372 T_names size_consts)) |
|
373 end; |
|
374 |
379 |
375 end; |
380 end; |