1 (* Title: HOL/Tools/Transfer/transfer_bnf.ML
2 Author: Ondrej Kuncar, TU Muenchen
4 Setup for Transfer for types that are BNF.
7 signature TRANSFER_BNF =
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
16 structure Transfer_BNF : TRANSFER_BNF =
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
31 val argT = hd (binder_types PT)
33 Const (@{const_name Domainp}, PT --> argT --> HOLogic.boolT) $ P
36 fun mk_pred pred_def args T =
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
42 list_comb (Const (pred_name, argsT ---> (T --> HOLogic.boolT)), args)
47 val argT = domain_type (fastype_of arg)
49 Const (@{const_name eq_onp}, (argT --> HOLogic.boolT) --> argT --> argT --> HOLogic.boolT)
54 Conv.top_sweep_conv (K (Conv.rewr_conv (safe_mk_meta_eq thm))) @{context}
56 fun type_name_of_bnf bnf = T_of_bnf bnf |> dest_Type |> fst
58 fun is_Type (Type _) = true
61 fun map_local_theory f = Named_Target.theory_init #> f #> Local_Theory.exit_global
63 fun bnf_only_type_ctr f bnf = if is_Type (T_of_bnf bnf) then f bnf else I
65 fun bnf_of_fp_sugar (fp_sugar:fp_sugar) = nth (#bnfs (#fp_res fp_sugar)) (#fp_res_index fp_sugar)
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
70 (* relation constraints - bi_total & co. *)
72 fun mk_relation_constraint name arg =
73 (Const (name, fastype_of arg --> HOLogic.boolT)) $ arg
75 fun side_constraint_tac bnf constr_defs ctxt i =
77 val thms = constr_defs @ map mk_sym [rel_eq_of_bnf bnf, rel_conversep_of_bnf bnf,
80 (SELECT_GOAL (Local_Defs.unfold_tac ctxt thms) THEN' rtac (rel_mono_of_bnf bnf)
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
88 fun generate_relation_constraint_goal ctxt bnf constraint_def =
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
96 ||>> mk_TFrees (dead_of_bnf bnf)
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)
108 fun prove_relation_side_constraint ctxt bnf constraint_def =
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)
115 Drule.zero_var_indexes (singleton (Variable.export ctxt old_ctxt) thm)
118 fun prove_relation_bi_constraint ctxt bnf constraint_def side_constraints =
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)
125 Drule.zero_var_indexes (singleton (Variable.export ctxt old_ctxt) thm)
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})]
131 fun prove_relation_constraints bnf lthy =
133 val transfer_attr = @{attributes [transfer_rule]}
134 val Tname = base_name_of_bnf bnf
135 fun qualify suffix = Binding.qualified true suffix Tname
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
151 [((Binding.empty, []), [([rel_eq_of_bnf bnf], @{attributes [relator_eq]})])]
153 (* predicator definition and Domainp and eq_onp theorem *)
155 fun define_pred bnf lthy =
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
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
180 fun Domainp_tac bnf pred_def ctxt i =
182 val n = live_of_bnf bnf
183 val set_map's = set_map_of_bnf bnf
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,
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
203 fun prove_Domainp_rel ctxt bnf pred_def =
205 val live = live_of_bnf bnf
207 val (((As, Bs), Ds), ctxt) = ctxt
210 ||>> mk_TFrees (dead_of_bnf bnf)
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)
222 Drule.zero_var_indexes (singleton (Variable.export ctxt old_ctxt) thm)
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
230 fun prove_rel_eq_onp ctxt bnf pred_def =
232 val live = live_of_bnf bnf
234 val ((As, Ds), ctxt) = ctxt
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)
247 Drule.zero_var_indexes (singleton (Variable.export ctxt old_ctxt) thm)
250 fun predicator bnf lthy =
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
270 (* BNF interpretation *)
272 fun transfer_bnf_interpretation bnf lthy =
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 []
278 val (pred_notes, lthy) = predicator bnf lthy
280 snd (Local_Theory.notes (constr_notes @ relator_eq_notes @ pred_notes) lthy)
283 val _ = Context.>> (Context.map_theory (bnf_interpretation
284 (bnf_only_type_ctr (fn bnf => map_local_theory (transfer_bnf_interpretation bnf)))))
286 (* simplification rules for the predicator *)
288 fun lookup_defined_pred_data lthy name =
289 case (Transfer.lookup_pred_data lthy name) of
291 | NONE => (error "lookup_pred_data: something went utterly wrong")
293 fun prove_pred_inject lthy (fp_sugar:fp_sugar) =
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)
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 =
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 =
316 val conj_cong = @{thm arg_cong2[of _ _ _ _ "op \<and>"]}
317 val start = @{thm eq_onp_same_args} RS conj_cong
319 @{thm eq_onp_same_args} RS (funpow (n - 2) (fn thm => start RS thm) start)
321 val n = if is_eqn thm then thm |> get_rhs |> HOLogic.dest_conj |> length else 0
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))
330 val rel_injects = #rel_injects fp_sugar
333 |> map rel2pred_massage
334 |> Variable.export lthy old_lthy
335 |> map Drule.zero_var_indexes
338 (* fp_sugar interpretation *)
340 fun transfer_fp_sugar_interpretation fp_sugar lthy =
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]}
347 snd (Local_Theory.note ((pred_inject_thm_name, simp_attrs), pred_injects) lthy)
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)))))