author | wenzelm |
Tue, 13 Aug 2024 18:53:24 +0200 | |
changeset 80701 | 39cd50407f79 |
parent 69593 | 3dda49e08b9d |
permissions | -rw-r--r-- |
55571 | 1 |
(* Title: HOL/Tools/BNF/bnf_lfp_rec_sugar_more.ML |
2 |
Author: Lorenz Panny, TU Muenchen |
|
3 |
Author: Jasmin Blanchette, TU Muenchen |
|
4 |
Copyright 2013 |
|
5 |
||
58315 | 6 |
More recursor sugar. |
55571 | 7 |
*) |
8 |
||
60000 | 9 |
signature BNF_LFP_REC_SUGAR_MORE = |
10 |
sig |
|
11 |
val massage_nested_rec_call: Proof.context -> (term -> bool) -> (typ -> typ -> term -> term) -> |
|
60002 | 12 |
(typ * typ -> term) -> typ list -> term -> term -> term -> term |
60000 | 13 |
end; |
14 |
||
15 |
structure BNF_LFP_Rec_Sugar_More : BNF_LFP_REC_SUGAR_MORE = |
|
55571 | 16 |
struct |
17 |
||
18 |
open BNF_Util |
|
66290 | 19 |
open BNF_Tactics |
55571 | 20 |
open BNF_Def |
21 |
open BNF_FP_Util |
|
22 |
open BNF_FP_Def_Sugar |
|
23 |
open BNF_FP_N2M_Sugar |
|
24 |
open BNF_LFP_Rec_Sugar |
|
25 |
||
58389 | 26 |
(* FIXME: remove "nat" cases throughout once it is registered as a datatype *) |
27 |
||
57993 | 28 |
val nested_simps = @{thms o_def[abs_def] id_def split fst_conv snd_conv}; |
55575
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
29 |
|
66290 | 30 |
fun special_endgame_tac ctxt fp_nesting_map_ident0s fp_nesting_map_comps fp_nesting_pred_maps = |
31 |
ALLGOALS (CONVERSION Thm.eta_long_conversion) THEN |
|
32 |
HEADGOAL (simp_tac (ss_only @{thms pred_fun_True_id} ctxt |
|
80701 | 33 |
|> Simplifier.add_proc \<^simproc>\<open>NO_MATCH\<close>)) THEN |
66290 | 34 |
unfold_thms_tac ctxt (nested_simps @ |
35 |
map (unfold_thms ctxt @{thms id_def}) (fp_nesting_map_ident0s @ fp_nesting_map_comps @ |
|
36 |
fp_nesting_pred_maps)) THEN |
|
37 |
ALLGOALS (rtac ctxt refl); |
|
38 |
||
69593 | 39 |
fun is_new_datatype _ \<^type_name>\<open>nat\<close> = true |
58389 | 40 |
| is_new_datatype ctxt s = |
63859
dca6fabd8060
make (co)induct component of 'fp_sugar' optional, for the benefit of nonuniform (co)datatypes and other similar extensions
blanchet
parents:
62326
diff
changeset
|
41 |
(case fp_sugar_of ctxt s of |
dca6fabd8060
make (co)induct component of 'fp_sugar' optional, for the benefit of nonuniform (co)datatypes and other similar extensions
blanchet
parents:
62326
diff
changeset
|
42 |
SOME {fp = Least_FP, fp_co_induct_sugar = SOME _, ...} => true |
dca6fabd8060
make (co)induct component of 'fp_sugar' optional, for the benefit of nonuniform (co)datatypes and other similar extensions
blanchet
parents:
62326
diff
changeset
|
43 |
| _ => false); |
55571 | 44 |
|
58461 | 45 |
fun basic_lfp_sugar_of C fun_arg_Tsss ({T, fp_res_index, fp_ctr_sugar = {ctr_sugar, ...}, |
63859
dca6fabd8060
make (co)induct component of 'fp_sugar' optional, for the benefit of nonuniform (co)datatypes and other similar extensions
blanchet
parents:
62326
diff
changeset
|
46 |
fp_co_induct_sugar = SOME {co_rec = recx, co_rec_thms = rec_thms, ...}, ...} : fp_sugar) = |
dca6fabd8060
make (co)induct component of 'fp_sugar' optional, for the benefit of nonuniform (co)datatypes and other similar extensions
blanchet
parents:
62326
diff
changeset
|
47 |
{T = T, fp_res_index = fp_res_index, C = C, fun_arg_Tsss = fun_arg_Tsss, ctr_sugar = ctr_sugar, |
dca6fabd8060
make (co)induct component of 'fp_sugar' optional, for the benefit of nonuniform (co)datatypes and other similar extensions
blanchet
parents:
62326
diff
changeset
|
48 |
recx = recx, rec_thms = rec_thms}; |
55571 | 49 |
|
69593 | 50 |
fun basic_lfp_sugars_of _ [\<^typ>\<open>nat\<close>] _ _ lthy = |
62326
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
51 |
([], [0], [nat_basic_lfp_sugar], [], [], [], TrueI (*dummy*), [], false, lthy) |
58389 | 52 |
| basic_lfp_sugars_of bs arg_Ts callers callssss0 lthy0 = |
53 |
let |
|
54 |
val ((missing_arg_Ts, perm0_kks, |
|
61760 | 55 |
fp_sugars as {fp_nesting_bnfs, |
63859
dca6fabd8060
make (co)induct component of 'fp_sugar' optional, for the benefit of nonuniform (co)datatypes and other similar extensions
blanchet
parents:
62326
diff
changeset
|
56 |
fp_co_induct_sugar = SOME {common_co_inducts = [common_induct], ...}, ...} :: _, |
58389 | 57 |
(lfp_sugar_thms, _)), lthy) = |
58 |
nested_to_mutual_fps (K true) Least_FP bs arg_Ts callers callssss0 lthy0; |
|
55574
4a940ebceef8
rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents:
55571
diff
changeset
|
59 |
|
58389 | 60 |
val induct_attrs = (case lfp_sugar_thms of SOME ((_, _, attrs), _) => attrs | NONE => []); |
58283
71d74e641538
preserve case names in '(co)induct' theorems generated by prim(co)rec'
blanchet
parents:
58131
diff
changeset
|
61 |
|
58389 | 62 |
val Ts = map #T fp_sugars; |
63 |
val Xs = map #X fp_sugars; |
|
63859
dca6fabd8060
make (co)induct component of 'fp_sugar' optional, for the benefit of nonuniform (co)datatypes and other similar extensions
blanchet
parents:
62326
diff
changeset
|
64 |
val Cs = map (body_type o fastype_of o #co_rec o the o #fp_co_induct_sugar) fp_sugars; |
58389 | 65 |
val Xs_TCs = Xs ~~ (Ts ~~ Cs); |
55574
4a940ebceef8
rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents:
55571
diff
changeset
|
66 |
|
58389 | 67 |
fun zip_XrecT (Type (s, Us)) = [Type (s, map (HOLogic.mk_tupleT o zip_XrecT) Us)] |
68 |
| zip_XrecT U = |
|
69 |
(case AList.lookup (op =) Xs_TCs U of |
|
70 |
SOME (T, C) => [T, C] |
|
71 |
| NONE => [U]); |
|
55574
4a940ebceef8
rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents:
55571
diff
changeset
|
72 |
|
58460 | 73 |
val ctrXs_Tsss = map (#ctrXs_Tss o #fp_ctr_sugar) fp_sugars; |
58389 | 74 |
val fun_arg_Tssss = map (map (map zip_XrecT)) ctrXs_Tsss; |
55574
4a940ebceef8
rewrote a small portion of code to avoid dependency on low-level constant
blanchet
parents:
55571
diff
changeset
|
75 |
|
58389 | 76 |
val fp_nesting_map_ident0s = map map_ident0_of_bnf fp_nesting_bnfs; |
77 |
val fp_nesting_map_comps = map map_comp_of_bnf fp_nesting_bnfs; |
|
62326
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
78 |
val fp_nesting_pred_maps = map pred_map_of_bnf fp_nesting_bnfs; |
58389 | 79 |
in |
58634
9f10d82e8188
added parameterized ML antiquotations @{map N}, @{fold N}, @{fold_map N}, @{split_list N};
wenzelm
parents:
58461
diff
changeset
|
80 |
(missing_arg_Ts, perm0_kks, @{map 3} basic_lfp_sugar_of Cs fun_arg_Tssss fp_sugars, |
62326
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
81 |
fp_nesting_map_ident0s, fp_nesting_map_comps, fp_nesting_pred_maps, common_induct, |
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
82 |
induct_attrs, is_some lfp_sugar_thms, lthy) |
58389 | 83 |
end; |
55571 | 84 |
|
58387 | 85 |
exception NO_MAP of term; |
55571 | 86 |
|
60002 | 87 |
fun massage_nested_rec_call ctxt has_call massage_fun massage_nonfun bound_Ts y y' t0 = |
55571 | 88 |
let |
64705
7596b0736ab9
more uniform errors in '(prim)(co)rec(ursive)' variants
blanchet
parents:
64627
diff
changeset
|
89 |
fun check_no_call t = if has_call t then unexpected_rec_call_in ctxt [t0] t else (); |
55571 | 90 |
|
91 |
val typof = curry fastype_of1 bound_Ts; |
|
64627
8d7cb22482e3
generalized ML function (towards nonuniform datatypes)
blanchet
parents:
63859
diff
changeset
|
92 |
val massage_no_call = build_map ctxt [] [] massage_nonfun; |
55571 | 93 |
|
94 |
val yT = typof y; |
|
95 |
val yU = typof y'; |
|
96 |
||
60002 | 97 |
fun y_of_y' () = massage_no_call (yU, yT) $ y'; |
55571 | 98 |
val elim_y = Term.map_aterms (fn t => if t = y then y_of_y' () else t); |
99 |
||
100 |
fun massage_mutual_fun U T t = |
|
101 |
(case t of |
|
69593 | 102 |
Const (\<^const_name>\<open>comp\<close>, _) $ t1 $ t2 => |
55571 | 103 |
mk_comp bound_Ts (tap check_no_call t1, massage_mutual_fun U T t2) |
104 |
| _ => |
|
60002 | 105 |
if has_call t then massage_fun U T t else mk_comp bound_Ts (t, massage_no_call (U, T))); |
55571 | 106 |
|
107 |
fun massage_map (Type (_, Us)) (Type (s, Ts)) t = |
|
108 |
(case try (dest_map ctxt s) t of |
|
109 |
SOME (map0, fs) => |
|
110 |
let |
|
111 |
val Type (_, ran_Ts) = range_type (typof t); |
|
112 |
val map' = mk_map (length fs) Us ran_Ts map0; |
|
58634
9f10d82e8188
added parameterized ML antiquotations @{map N}, @{fold N}, @{fold_map N}, @{split_list N};
wenzelm
parents:
58461
diff
changeset
|
113 |
val fs' = map_flattened_map_args ctxt s (@{map 3} massage_map_or_map_arg Us Ts) fs; |
55571 | 114 |
in |
115 |
Term.list_comb (map', fs') |
|
116 |
end |
|
62326
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
117 |
| NONE => |
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
118 |
(case try (dest_pred ctxt s) t of |
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
119 |
SOME (pred0, fs) => |
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
120 |
let |
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
121 |
val pred' = mk_pred Us pred0; |
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
122 |
val fs' = map_flattened_map_args ctxt s (@{map 3} massage_map_or_map_arg Us Ts) fs; |
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
123 |
in |
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
124 |
Term.list_comb (pred', fs') |
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
125 |
end |
3cf7a067599c
allow predicator instead of map function in 'primrec'
blanchet
parents:
61760
diff
changeset
|
126 |
| NONE => raise NO_MAP t)) |
58387 | 127 |
| massage_map _ _ t = raise NO_MAP t |
55571 | 128 |
and massage_map_or_map_arg U T t = |
129 |
if T = U then |
|
130 |
tap check_no_call t |
|
131 |
else |
|
132 |
massage_map U T t |
|
58387 | 133 |
handle NO_MAP _ => massage_mutual_fun U T t; |
55571 | 134 |
|
60001 | 135 |
fun massage_outer_call (t as t1 $ t2) = |
55571 | 136 |
if has_call t then |
137 |
if t2 = y then |
|
138 |
massage_map yU yT (elim_y t1) $ y' |
|
64705
7596b0736ab9
more uniform errors in '(prim)(co)rec(ursive)' variants
blanchet
parents:
64627
diff
changeset
|
139 |
handle NO_MAP t' => invalid_map ctxt [t0] t' |
55571 | 140 |
else |
141 |
let val (g, xs) = Term.strip_comb t2 in |
|
142 |
if g = y then |
|
64705
7596b0736ab9
more uniform errors in '(prim)(co)rec(ursive)' variants
blanchet
parents:
64627
diff
changeset
|
143 |
if exists has_call xs then unexpected_rec_call_in ctxt [t0] t2 |
60001 | 144 |
else Term.list_comb (massage_outer_call (mk_compN (length xs) bound_Ts (t1, y)), xs) |
55571 | 145 |
else |
146 |
ill_formed_rec_call ctxt t |
|
147 |
end |
|
148 |
else |
|
149 |
elim_y t |
|
60001 | 150 |
| massage_outer_call t = if t = y then y_of_y' () else ill_formed_rec_call ctxt t; |
55571 | 151 |
in |
60001 | 152 |
massage_outer_call t0 |
55571 | 153 |
end; |
154 |
||
60001 | 155 |
fun rewrite_map_fun ctxt get_ctr_pos U T t = |
55575
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
156 |
let |
60001 | 157 |
val _ = |
158 |
(case try HOLogic.dest_prodT U of |
|
64705
7596b0736ab9
more uniform errors in '(prim)(co)rec(ursive)' variants
blanchet
parents:
64627
diff
changeset
|
159 |
SOME (U1, _) => U1 = T orelse invalid_map ctxt [] t |
7596b0736ab9
more uniform errors in '(prim)(co)rec(ursive)' variants
blanchet
parents:
64627
diff
changeset
|
160 |
| NONE => invalid_map ctxt [] t); |
55575
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
161 |
|
60001 | 162 |
fun subst d (t as Bound d') = t |> d = SOME d' ? curry (op $) (fst_const U) |
55575
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
163 |
| subst d (Abs (v, T, b)) = |
60001 | 164 |
Abs (v, if d = SOME ~1 then U else T, subst (Option.map (Integer.add 1) d) b) |
55575
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
165 |
| subst d t = |
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
166 |
let |
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
167 |
val (u, vs) = strip_comb t; |
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
168 |
val ctr_pos = try (get_ctr_pos o fst o dest_Free) u |> the_default ~1; |
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
169 |
in |
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
170 |
if ctr_pos >= 0 then |
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
171 |
if d = SOME ~1 andalso length vs = ctr_pos then |
60001 | 172 |
Term.list_comb (permute_args ctr_pos (snd_const U), vs) |
55575
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
173 |
else if length vs > ctr_pos andalso is_some d andalso |
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
174 |
d = try (fn Bound n => n) (nth vs ctr_pos) then |
60001 | 175 |
Term.list_comb (snd_const U $ nth vs ctr_pos, map (subst d) (nth_drop ctr_pos vs)) |
55575
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
176 |
else |
64705
7596b0736ab9
more uniform errors in '(prim)(co)rec(ursive)' variants
blanchet
parents:
64627
diff
changeset
|
177 |
rec_call_not_apply_to_ctr_arg ctxt [] t |
55575
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
178 |
else |
60001 | 179 |
Term.list_comb (u, map (subst (if d = SOME ~1 then NONE else d)) vs) |
180 |
end; |
|
55575
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
181 |
in |
60001 | 182 |
subst (SOME ~1) t |
55575
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
183 |
end; |
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
184 |
|
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
185 |
fun rewrite_nested_rec_call ctxt has_call get_ctr_pos = |
60002 | 186 |
massage_nested_rec_call ctxt has_call (rewrite_map_fun ctxt get_ctr_pos) (fst_const o fst); |
55575
a5e33e18fb5c
moved 'primrec' up (for real this time) and removed temporary 'old_primrec'
blanchet
parents:
55574
diff
changeset
|
187 |
|
55571 | 188 |
val _ = Theory.setup (register_lfp_rec_extension |
66290 | 189 |
{nested_simps = nested_simps, special_endgame_tac = special_endgame_tac, |
190 |
is_new_datatype = is_new_datatype, basic_lfp_sugars_of = basic_lfp_sugars_of, |
|
58389 | 191 |
rewrite_nested_rec_call = SOME rewrite_nested_rec_call}); |
55571 | 192 |
|
193 |
end; |