|
1 (* Title: HOL/Tools/Transfer/transfer_bnf.ML |
|
2 Author: Ondrej Kuncar, TU Muenchen |
|
3 |
|
4 Setup for Transfer for types that are BNF. |
|
5 *) |
|
6 |
|
7 signature TRANSFER_BNF = |
|
8 sig |
|
9 val base_name_of_bnf: BNF_Def.bnf -> binding |
|
10 val type_name_of_bnf: BNF_Def.bnf -> string |
|
11 val lookup_defined_pred_data: Proof.context -> string -> Transfer.pred_data |
|
12 val map_local_theory: (local_theory -> local_theory) -> theory -> theory |
|
13 val bnf_only_type_ctr: (BNF_Def.bnf -> 'a -> 'a) -> BNF_Def.bnf -> 'a -> 'a |
|
14 end |
|
15 |
|
16 structure Transfer_BNF : TRANSFER_BNF = |
|
17 struct |
|
18 |
|
19 open BNF_Util |
|
20 open BNF_Def |
|
21 open BNF_FP_Def_Sugar |
|
22 |
|
23 (* util functions *) |
|
24 |
|
25 fun base_name_of_bnf bnf = Binding.name (Binding.name_of (name_of_bnf bnf)) |
|
26 fun mk_Frees_free x Ts ctxt = Variable.variant_frees ctxt [] (mk_names (length Ts) x ~~ Ts) |> map Free |
|
27 |
|
28 fun mk_Domainp P = |
|
29 let |
|
30 val PT = fastype_of P |
|
31 val argT = hd (binder_types PT) |
|
32 in |
|
33 Const (@{const_name Domainp}, PT --> argT --> HOLogic.boolT) $ P |
|
34 end |
|
35 |
|
36 fun mk_pred pred_def args T = |
|
37 let |
|
38 val pred_name = pred_def |> prop_of |> HOLogic.dest_Trueprop |> fst o HOLogic.dest_eq |
|
39 |> head_of |> fst o dest_Const |
|
40 val argsT = map fastype_of args |
|
41 in |
|
42 list_comb (Const (pred_name, argsT ---> (T --> HOLogic.boolT)), args) |
|
43 end |
|
44 |
|
45 fun mk_eq_onp arg = |
|
46 let |
|
47 val argT = domain_type (fastype_of arg) |
|
48 in |
|
49 Const (@{const_name eq_onp}, (argT --> HOLogic.boolT) --> argT --> argT --> HOLogic.boolT) |
|
50 $ arg |
|
51 end |
|
52 |
|
53 fun subst_conv thm = |
|
54 Conv.top_sweep_conv (K (Conv.rewr_conv (safe_mk_meta_eq thm))) @{context} |
|
55 |
|
56 fun type_name_of_bnf bnf = T_of_bnf bnf |> dest_Type |> fst |
|
57 |
|
58 fun is_Type (Type _) = true |
|
59 | is_Type _ = false |
|
60 |
|
61 fun map_local_theory f = Named_Target.theory_init #> f #> Local_Theory.exit_global |
|
62 |
|
63 fun bnf_only_type_ctr f bnf = if is_Type (T_of_bnf bnf) then f bnf else I |
|
64 |
|
65 fun bnf_of_fp_sugar (fp_sugar:fp_sugar) = nth (#bnfs (#fp_res fp_sugar)) (#fp_res_index fp_sugar) |
|
66 |
|
67 fun fp_sugar_only_type_ctr f fp_sugar = |
|
68 if is_Type (T_of_bnf (bnf_of_fp_sugar fp_sugar)) then f fp_sugar else I |
|
69 |
|
70 (* relation constraints - bi_total & co. *) |
|
71 |
|
72 fun mk_relation_constraint name arg = |
|
73 (Const (name, fastype_of arg --> HOLogic.boolT)) $ arg |
|
74 |
|
75 fun side_constraint_tac bnf constr_defs ctxt i = |
|
76 let |
|
77 val thms = constr_defs @ map mk_sym [rel_eq_of_bnf bnf, rel_conversep_of_bnf bnf, |
|
78 rel_OO_of_bnf bnf] |
|
79 in |
|
80 (SELECT_GOAL (Local_Defs.unfold_tac ctxt thms) THEN' rtac (rel_mono_of_bnf bnf) |
|
81 THEN_ALL_NEW atac) i |
|
82 end |
|
83 |
|
84 fun bi_constraint_tac constr_iff sided_constr_intros ctxt i = |
|
85 (SELECT_GOAL (Local_Defs.unfold_tac ctxt [constr_iff]) THEN' |
|
86 CONJ_WRAP' (fn thm => rtac thm THEN_ALL_NEW (REPEAT_DETERM o etac conjE THEN' atac)) sided_constr_intros) i |
|
87 |
|
88 fun generate_relation_constraint_goal ctxt bnf constraint_def = |
|
89 let |
|
90 val constr_name = constraint_def |> prop_of |> HOLogic.dest_Trueprop |> fst o HOLogic.dest_eq |
|
91 |> head_of |> fst o dest_Const |
|
92 val live = live_of_bnf bnf |
|
93 val (((As, Bs), Ds), ctxt) = ctxt |
|
94 |> mk_TFrees live |
|
95 ||>> mk_TFrees live |
|
96 ||>> mk_TFrees (dead_of_bnf bnf) |
|
97 |
|
98 val relator = mk_rel_of_bnf Ds As Bs bnf |
|
99 val relsT = map2 mk_pred2T As Bs |
|
100 val (args, ctxt) = Ctr_Sugar_Util.mk_Frees "R" relsT ctxt |
|
101 val concl = HOLogic.mk_Trueprop (mk_relation_constraint constr_name (list_comb (relator, args))) |
|
102 val assms = map (HOLogic.mk_Trueprop o (mk_relation_constraint constr_name)) args |
|
103 val goal = Logic.list_implies (assms, concl) |
|
104 in |
|
105 (goal, ctxt) |
|
106 end |
|
107 |
|
108 fun prove_relation_side_constraint ctxt bnf constraint_def = |
|
109 let |
|
110 val old_ctxt = ctxt |
|
111 val (goal, ctxt) = generate_relation_constraint_goal ctxt bnf constraint_def |
|
112 val thm = Goal.prove ctxt [] [] goal |
|
113 (fn {context = ctxt, prems = _} => side_constraint_tac bnf [constraint_def] ctxt 1) |
|
114 in |
|
115 Drule.zero_var_indexes (singleton (Variable.export ctxt old_ctxt) thm) |
|
116 end |
|
117 |
|
118 fun prove_relation_bi_constraint ctxt bnf constraint_def side_constraints = |
|
119 let |
|
120 val old_ctxt = ctxt |
|
121 val (goal, ctxt) = generate_relation_constraint_goal ctxt bnf constraint_def |
|
122 val thm = Goal.prove ctxt [] [] goal |
|
123 (fn {context = ctxt, prems = _} => bi_constraint_tac constraint_def side_constraints ctxt 1) |
|
124 in |
|
125 Drule.zero_var_indexes (singleton (Variable.export ctxt old_ctxt) thm) |
|
126 end |
|
127 |
|
128 val defs = [("left_total_rel", @{thm left_total_alt_def}), ("right_total_rel", @{thm right_total_alt_def}), |
|
129 ("left_unique_rel", @{thm left_unique_alt_def}), ("right_unique_rel", @{thm right_unique_alt_def})] |
|
130 |
|
131 fun prove_relation_constraints bnf lthy = |
|
132 let |
|
133 val transfer_attr = @{attributes [transfer_rule]} |
|
134 val Tname = base_name_of_bnf bnf |
|
135 fun qualify suffix = Binding.qualified true suffix Tname |
|
136 |
|
137 val defs = map (apsnd (prove_relation_side_constraint lthy bnf)) defs |
|
138 val bi_total = prove_relation_bi_constraint lthy bnf @{thm bi_total_alt_def} |
|
139 [snd (nth defs 0), snd (nth defs 1)] |
|
140 val bi_unique = prove_relation_bi_constraint lthy bnf @{thm bi_unique_alt_def} |
|
141 [snd (nth defs 2), snd (nth defs 3)] |
|
142 val defs = ("bi_total_rel", bi_total) :: ("bi_unique_rel", bi_unique) :: defs |
|
143 val notes = maps (fn (name, thm) => [((qualify name, []), [([thm], transfer_attr)])]) defs |
|
144 in |
|
145 notes |
|
146 end |
|
147 |
|
148 (* relator_eq *) |
|
149 |
|
150 fun relator_eq bnf = |
|
151 [((Binding.empty, []), [([rel_eq_of_bnf bnf], @{attributes [relator_eq]})])] |
|
152 |
|
153 (* predicator definition and Domainp and eq_onp theorem *) |
|
154 |
|
155 fun define_pred bnf lthy = |
|
156 let |
|
157 fun mk_pred_name c = Binding.prefix_name "pred_" c |
|
158 val live = live_of_bnf bnf |
|
159 val Tname = base_name_of_bnf bnf |
|
160 val ((As, Ds), lthy) = lthy |
|
161 |> mk_TFrees live |
|
162 ||>> mk_TFrees (dead_of_bnf bnf) |
|
163 val T = mk_T_of_bnf Ds As bnf |
|
164 val sets = mk_sets_of_bnf (replicate live Ds) (replicate live As) bnf |
|
165 val argTs = map mk_pred1T As |
|
166 val args = mk_Frees_free "P" argTs lthy |
|
167 val conjs = map (fn (set, arg) => mk_Ball (set $ Bound 0) arg) (sets ~~ args) |
|
168 val rhs = Abs ("x", T, foldr1 HOLogic.mk_conj conjs) |
|
169 val pred_name = mk_pred_name Tname |
|
170 val headT = argTs ---> (T --> HOLogic.boolT) |
|
171 val head = Free (Binding.name_of pred_name, headT) |
|
172 val lhs = list_comb (head, args) |
|
173 val def = HOLogic.mk_Trueprop (HOLogic.mk_eq (lhs, rhs)) |
|
174 val ((_, (_, pred_def)), lthy) = Specification.definition ((SOME (pred_name, SOME headT, NoSyn)), |
|
175 ((Binding.empty, []), def)) lthy |
|
176 in |
|
177 (pred_def, lthy) |
|
178 end |
|
179 |
|
180 fun Domainp_tac bnf pred_def ctxt i = |
|
181 let |
|
182 val n = live_of_bnf bnf |
|
183 val set_map's = set_map_of_bnf bnf |
|
184 in |
|
185 EVERY' [rtac ext, SELECT_GOAL (Local_Defs.unfold_tac ctxt [@{thm Domainp.simps}, |
|
186 in_rel_of_bnf bnf, pred_def]), rtac iffI, |
|
187 REPEAT_DETERM o eresolve_tac [exE, conjE, CollectE], hyp_subst_tac ctxt, |
|
188 CONJ_WRAP' (fn set_map => EVERY' [rtac ballI, dtac (set_map RS equalityD1 RS set_mp), |
|
189 etac imageE, dtac set_rev_mp, atac, REPEAT_DETERM o eresolve_tac [CollectE, @{thm case_prodE}], |
|
190 hyp_subst_tac ctxt, rtac @{thm iffD2[OF arg_cong2[of _ _ _ _ Domainp, OF refl fst_conv]]}, |
|
191 etac @{thm DomainPI}]) set_map's, |
|
192 REPEAT_DETERM o etac conjE, REPEAT_DETERM o resolve_tac [exI, (refl RS conjI), rotate_prems 1 conjI], |
|
193 rtac refl, rtac (box_equals OF [map_cong0_of_bnf bnf, map_comp_of_bnf bnf RS sym, |
|
194 map_id_of_bnf bnf]), |
|
195 REPEAT_DETERM_N n o (EVERY' [rtac @{thm box_equals[OF _ sym[OF o_apply] sym[OF id_apply]]}, |
|
196 rtac @{thm fst_conv}]), rtac CollectI, |
|
197 CONJ_WRAP' (fn set_map => EVERY' [rtac (set_map RS @{thm ord_eq_le_trans}), |
|
198 REPEAT_DETERM o resolve_tac [@{thm image_subsetI}, CollectI, @{thm case_prodI}], |
|
199 dtac (rotate_prems 1 bspec), atac, etac @{thm DomainpE}, etac @{thm someI}]) set_map's |
|
200 ] i |
|
201 end |
|
202 |
|
203 fun prove_Domainp_rel ctxt bnf pred_def = |
|
204 let |
|
205 val live = live_of_bnf bnf |
|
206 val old_ctxt = ctxt |
|
207 val (((As, Bs), Ds), ctxt) = ctxt |
|
208 |> mk_TFrees live |
|
209 ||>> mk_TFrees live |
|
210 ||>> mk_TFrees (dead_of_bnf bnf) |
|
211 |
|
212 val relator = mk_rel_of_bnf Ds As Bs bnf |
|
213 val relsT = map2 mk_pred2T As Bs |
|
214 val T = mk_T_of_bnf Ds As bnf |
|
215 val (args, ctxt) = Ctr_Sugar_Util.mk_Frees "R" relsT ctxt |
|
216 val lhs = mk_Domainp (list_comb (relator, args)) |
|
217 val rhs = mk_pred pred_def (map mk_Domainp args) T |
|
218 val goal = HOLogic.mk_eq (lhs, rhs) |> HOLogic.mk_Trueprop |
|
219 val thm = Goal.prove ctxt [] [] goal |
|
220 (fn {context = ctxt, prems = _} => Domainp_tac bnf pred_def ctxt 1) |
|
221 in |
|
222 Drule.zero_var_indexes (singleton (Variable.export ctxt old_ctxt) thm) |
|
223 end |
|
224 |
|
225 fun pred_eq_onp_tac bnf pred_def ctxt i = |
|
226 (SELECT_GOAL (Local_Defs.unfold_tac ctxt [@{thm eq_onp_Grp}, |
|
227 @{thm Ball_Collect}, pred_def]) THEN' CONVERSION (subst_conv (map_id0_of_bnf bnf RS sym)) |
|
228 THEN' rtac (rel_Grp_of_bnf bnf)) i |
|
229 |
|
230 fun prove_rel_eq_onp ctxt bnf pred_def = |
|
231 let |
|
232 val live = live_of_bnf bnf |
|
233 val old_ctxt = ctxt |
|
234 val ((As, Ds), ctxt) = ctxt |
|
235 |> mk_TFrees live |
|
236 ||>> mk_TFrees (dead_of_bnf bnf) |
|
237 val T = mk_T_of_bnf Ds As bnf |
|
238 val argTs = map mk_pred1T As |
|
239 val (args, ctxt) = mk_Frees "P" argTs ctxt |
|
240 val relator = mk_rel_of_bnf Ds As As bnf |
|
241 val lhs = list_comb (relator, map mk_eq_onp args) |
|
242 val rhs = mk_eq_onp (mk_pred pred_def args T) |
|
243 val goal = HOLogic.mk_eq (lhs, rhs) |> HOLogic.mk_Trueprop |
|
244 val thm = Goal.prove ctxt [] [] goal |
|
245 (fn {context = ctxt, prems = _} => pred_eq_onp_tac bnf pred_def ctxt 1) |
|
246 in |
|
247 Drule.zero_var_indexes (singleton (Variable.export ctxt old_ctxt) thm) |
|
248 end |
|
249 |
|
250 fun predicator bnf lthy = |
|
251 let |
|
252 val (pred_def, lthy) = define_pred bnf lthy |
|
253 val pred_def = Morphism.thm (Local_Theory.target_morphism lthy) pred_def |
|
254 val Domainp_rel = prove_Domainp_rel lthy bnf pred_def |
|
255 val rel_eq_onp = prove_rel_eq_onp lthy bnf pred_def |
|
256 fun qualify defname suffix = Binding.qualified true suffix defname |
|
257 val Domainp_rel_thm_name = qualify (base_name_of_bnf bnf) "Domainp_rel" |
|
258 val rel_eq_onp_thm_name = qualify (base_name_of_bnf bnf) "rel_eq_onp" |
|
259 val pred_data = {rel_eq_onp = rel_eq_onp} |
|
260 val type_name = type_name_of_bnf bnf |
|
261 val relator_domain_attr = @{attributes [relator_domain]} |
|
262 val notes = [((Domainp_rel_thm_name, []), [([Domainp_rel], relator_domain_attr)]), |
|
263 ((rel_eq_onp_thm_name, []), [([rel_eq_onp], [])])] |
|
264 val lthy = Local_Theory.declaration {syntax = false, pervasive = true} |
|
265 (fn phi => Transfer.update_pred_data type_name (Transfer.morph_pred_data phi pred_data)) lthy |
|
266 in |
|
267 (notes, lthy) |
|
268 end |
|
269 |
|
270 (* BNF interpretation *) |
|
271 |
|
272 fun transfer_bnf_interpretation bnf lthy = |
|
273 let |
|
274 val constr_notes = if dead_of_bnf bnf > 0 then [] |
|
275 else prove_relation_constraints bnf lthy |
|
276 val relator_eq_notes = if dead_of_bnf bnf > 0 then [] |
|
277 else relator_eq bnf |
|
278 val (pred_notes, lthy) = predicator bnf lthy |
|
279 in |
|
280 snd (Local_Theory.notes (constr_notes @ relator_eq_notes @ pred_notes) lthy) |
|
281 end |
|
282 |
|
283 val _ = Context.>> (Context.map_theory (bnf_interpretation |
|
284 (bnf_only_type_ctr (fn bnf => map_local_theory (transfer_bnf_interpretation bnf))))) |
|
285 |
|
286 (* simplification rules for the predicator *) |
|
287 |
|
288 fun lookup_defined_pred_data lthy name = |
|
289 case (Transfer.lookup_pred_data lthy name) of |
|
290 SOME data => data |
|
291 | NONE => (error "lookup_pred_data: something went utterly wrong") |
|
292 |
|
293 fun prove_pred_inject lthy (fp_sugar:fp_sugar) = |
|
294 let |
|
295 val involved_types = distinct op= ( |
|
296 map type_name_of_bnf (#nested_bnfs fp_sugar) |
|
297 @ map type_name_of_bnf (#nesting_bnfs fp_sugar) |
|
298 @ map type_name_of_bnf (#bnfs (#fp_res fp_sugar))) |
|
299 val eq_onps = map (Transfer.rel_eq_onp o lookup_defined_pred_data lthy) involved_types |
|
300 val live = live_of_bnf (bnf_of_fp_sugar fp_sugar) |
|
301 val old_lthy = lthy |
|
302 val (As, lthy) = mk_TFrees live lthy |
|
303 val predTs = map mk_pred1T As |
|
304 val (preds, lthy) = mk_Frees "P" predTs lthy |
|
305 val args = map mk_eq_onp preds |
|
306 val cTs = map (SOME o certifyT lthy) (maps (replicate 2) As) |
|
307 val cts = map (SOME o certify lthy) args |
|
308 fun get_rhs thm = thm |> concl_of |> HOLogic.dest_Trueprop |> HOLogic.dest_eq |> snd |
|
309 fun is_eqn thm = can get_rhs thm |
|
310 fun rel2pred_massage thm = |
|
311 let |
|
312 fun pred_eq_onp_conj 0 = error "not defined" |
|
313 | pred_eq_onp_conj 1 = @{thm eq_onp_same_args} |
|
314 | pred_eq_onp_conj n = |
|
315 let |
|
316 val conj_cong = @{thm arg_cong2[of _ _ _ _ "op \<and>"]} |
|
317 val start = @{thm eq_onp_same_args} RS conj_cong |
|
318 in |
|
319 @{thm eq_onp_same_args} RS (funpow (n - 2) (fn thm => start RS thm) start) |
|
320 end |
|
321 val n = if is_eqn thm then thm |> get_rhs |> HOLogic.dest_conj |> length else 0 |
|
322 in |
|
323 thm |
|
324 |> Drule.instantiate' cTs cts |
|
325 |> Local_Defs.unfold lthy eq_onps |
|
326 |> (fn thm => if n > 0 then @{thm box_equals} |
|
327 OF [thm, @{thm eq_onp_same_args}, pred_eq_onp_conj n] |
|
328 else thm RS (@{thm eq_onp_same_args} RS iffD1)) |
|
329 end |
|
330 val rel_injects = #rel_injects fp_sugar |
|
331 in |
|
332 rel_injects |
|
333 |> map rel2pred_massage |
|
334 |> Variable.export lthy old_lthy |
|
335 |> map Drule.zero_var_indexes |
|
336 end |
|
337 |
|
338 (* fp_sugar interpretation *) |
|
339 |
|
340 fun transfer_fp_sugar_interpretation fp_sugar lthy = |
|
341 let |
|
342 val pred_injects = prove_pred_inject lthy fp_sugar |
|
343 fun qualify defname suffix = Binding.qualified true suffix defname |
|
344 val pred_inject_thm_name = qualify (base_name_of_bnf (bnf_of_fp_sugar fp_sugar)) "pred_inject" |
|
345 val simp_attrs = @{attributes [simp]} |
|
346 in |
|
347 snd (Local_Theory.note ((pred_inject_thm_name, simp_attrs), pred_injects) lthy) |
|
348 end |
|
349 |
|
350 val _ = Context.>> (Context.map_theory (fp_sugar_interpretation |
|
351 (fp_sugar_only_type_ctr (fn fp_sugar => map_local_theory (transfer_fp_sugar_interpretation fp_sugar))))) |
|
352 |
|
353 end |