author | wenzelm |
Mon, 21 Aug 2023 15:04:22 +0200 | |
changeset 78554 | 54991440905e |
parent 78022 | c078a33c2dff |
child 80636 | 4041e7c8059d |
permissions | -rw-r--r-- |
6070 | 1 |
(* Title: ZF/Tools/induct_tacs.ML |
6065 | 2 |
Author: Lawrence C Paulson, Cambridge University Computer Laboratory |
3 |
Copyright 1994 University of Cambridge |
|
4 |
||
12204 | 5 |
Induction and exhaustion tactics for Isabelle/ZF. The theory |
6 |
information needed to support them (and to support primrec). Also a |
|
7 |
function to install other sets as if they were datatypes. |
|
6065 | 8 |
*) |
9 |
||
10 |
signature DATATYPE_TACTICS = |
|
11 |
sig |
|
59788 | 12 |
val exhaust_tac: Proof.context -> string -> (binding * string option * mixfix) list -> |
13 |
int -> tactic |
|
14 |
val induct_tac: Proof.context -> string -> (binding * string option * mixfix) list -> |
|
15 |
int -> tactic |
|
12204 | 16 |
val rep_datatype_i: thm -> thm -> thm list -> thm list -> theory -> theory |
58011
bc6bced136e5
tuned signature -- moved type src to Token, without aliases;
wenzelm
parents:
56231
diff
changeset
|
17 |
val rep_datatype: Facts.ref * Token.src list -> Facts.ref * Token.src list -> |
bc6bced136e5
tuned signature -- moved type src to Token, without aliases;
wenzelm
parents:
56231
diff
changeset
|
18 |
(Facts.ref * Token.src list) list -> (Facts.ref * Token.src list) list -> theory -> theory |
6065 | 19 |
end; |
20 |
||
21 |
||
6070 | 22 |
(** Datatype information, e.g. associated theorems **) |
23 |
||
24 |
type datatype_info = |
|
12175 | 25 |
{inductive: bool, (*true if inductive, not coinductive*) |
6070 | 26 |
constructors : term list, (*the constructors, as Consts*) |
27 |
rec_rewrites : thm list, (*recursor equations*) |
|
28 |
case_rewrites : thm list, (*case equations*) |
|
29 |
induct : thm, |
|
30 |
mutual_induct : thm, |
|
31 |
exhaustion : thm}; |
|
32 |
||
33522 | 33 |
structure DatatypesData = Theory_Data |
22846 | 34 |
( |
6070 | 35 |
type T = datatype_info Symtab.table; |
36 |
val empty = Symtab.empty; |
|
33522 | 37 |
fun merge data : T = Symtab.merge (K true) data; |
22846 | 38 |
); |
6070 | 39 |
|
40 |
||
41 |
||
42 |
(** Constructor information: needed to map constructors to datatypes **) |
|
43 |
||
44 |
type constructor_info = |
|
45 |
{big_rec_name : string, (*name of the mutually recursive set*) |
|
46 |
constructors : term list, (*the constructors, as Consts*) |
|
6141 | 47 |
free_iffs : thm list, (*freeness simprules*) |
6070 | 48 |
rec_rewrites : thm list}; (*recursor equations*) |
49 |
||
50 |
||
33522 | 51 |
structure ConstructorsData = Theory_Data |
22846 | 52 |
( |
6070 | 53 |
type T = constructor_info Symtab.table |
54 |
val empty = Symtab.empty |
|
33522 | 55 |
fun merge data = Symtab.merge (K true) data; |
22846 | 56 |
); |
6070 | 57 |
|
6065 | 58 |
structure DatatypeTactics : DATATYPE_TACTICS = |
59 |
struct |
|
60 |
||
16458 | 61 |
fun datatype_info thy name = |
17412 | 62 |
(case Symtab.lookup (DatatypesData.get thy) name of |
15531 | 63 |
SOME info => info |
64 |
| NONE => error ("Unknown datatype " ^ quote name)); |
|
6065 | 65 |
|
66 |
||
67 |
(*Given a variable, find the inductive set associated it in the assumptions*) |
|
14153 | 68 |
exception Find_tname of string |
69 |
||
37780 | 70 |
fun find_tname ctxt var As = |
74294 | 71 |
let fun mk_pair \<^Const_>\<open>mem for \<open>Free (v,_)\<close> A\<close> = (v, #1 (dest_Const (head_of A))) |
12175 | 72 |
| mk_pair _ = raise Match |
74342 | 73 |
val pairs = map_filter (try (mk_pair o \<^dest_judgment>)) As |
37780 | 74 |
val x = |
75 |
(case try (dest_Free o Syntax.read_term ctxt) var of |
|
76 |
SOME (x, _) => x |
|
77 |
| _ => raise Find_tname ("Bad variable " ^ quote var)) |
|
78 |
in case AList.lookup (op =) pairs x of |
|
15531 | 79 |
NONE => raise Find_tname ("Cannot determine datatype of " ^ quote var) |
80 |
| SOME t => t |
|
6065 | 81 |
end; |
82 |
||
12175 | 83 |
(** generic exhaustion and induction tactic for datatypes |
84 |
Differences from HOL: |
|
6065 | 85 |
(1) no checking if the induction var occurs in premises, since it always |
86 |
appears in one of them, and it's hard to check for other occurrences |
|
87 |
(2) exhaustion works for VARIABLES in the premises, not general terms |
|
88 |
**) |
|
89 |
||
59788 | 90 |
fun exhaust_induct_tac exh ctxt var fixes i state = SUBGOAL (fn _ => |
6065 | 91 |
let |
42361 | 92 |
val thy = Proof_Context.theory_of ctxt |
60695
757549b4bbe6
Variable.focus etc.: optional bindings provided by user;
wenzelm
parents:
59936
diff
changeset
|
93 |
val ({context = ctxt', asms, ...}, _) = Subgoal.focus ctxt i NONE state |
59582 | 94 |
val tn = find_tname ctxt' var (map Thm.term_of asms) |
12175 | 95 |
val rule = |
70474 | 96 |
datatype_info thy tn |
97 |
|> (if exh then #exhaustion else #induct) |
|
98 |
|> Thm.transfer thy; |
|
74294 | 99 |
val \<^Const_>\<open>mem for \<open>Var(ixn,_)\<close> _\<close> = |
59582 | 100 |
(case Thm.prems_of rule of |
12175 | 101 |
[] => error "induction is not available for this datatype" |
74342 | 102 |
| major::_ => \<^dest_judgment> major) |
6065 | 103 |
in |
59788 | 104 |
Rule_Insts.eres_inst_tac ctxt [((ixn, Position.none), var)] fixes rule i |
14153 | 105 |
end |
106 |
handle Find_tname msg => |
|
107 |
if exh then (*try boolean case analysis instead*) |
|
59788 | 108 |
case_tac ctxt var fixes i |
56231
b98813774a63
enforce subgoal boundaries via SUBGOAL/SUBGOAL_CASES -- clean tactical failure if out-of-range;
wenzelm
parents:
55740
diff
changeset
|
109 |
else error msg) i state; |
6065 | 110 |
|
111 |
val exhaust_tac = exhaust_induct_tac true; |
|
112 |
val induct_tac = exhaust_induct_tac false; |
|
113 |
||
6070 | 114 |
|
115 |
(**** declare non-datatype as datatype ****) |
|
116 |
||
117 |
fun rep_datatype_i elim induct case_eqns recursor_eqns thy = |
|
118 |
let |
|
119 |
(*analyze the LHS of a case equation to get a constructor*) |
|
74294 | 120 |
fun const_of \<^Const_>\<open>IFOL.eq _ for \<open>_ $ c\<close> _\<close> = c |
6070 | 121 |
| const_of eqn = error ("Ill-formed case equation: " ^ |
26939
1035c89b4c02
moved global pretty/string_of functions from Sign to Syntax;
wenzelm
parents:
26618
diff
changeset
|
122 |
Syntax.string_of_term_global thy eqn); |
6070 | 123 |
|
124 |
val constructors = |
|
74342 | 125 |
map (head_of o const_of o \<^dest_judgment> o Thm.prop_of) case_eqns; |
6070 | 126 |
|
74342 | 127 |
val \<^Const_>\<open>mem for _ data\<close> = \<^dest_judgment> (hd (Thm.prems_of elim)); |
12175 | 128 |
|
6112 | 129 |
val Const(big_rec_name, _) = head_of data; |
130 |
||
6070 | 131 |
val simps = case_eqns @ recursor_eqns; |
132 |
||
133 |
val dt_info = |
|
12175 | 134 |
{inductive = true, |
135 |
constructors = constructors, |
|
70474 | 136 |
rec_rewrites = map Thm.trim_context recursor_eqns, |
137 |
case_rewrites = map Thm.trim_context case_eqns, |
|
138 |
induct = Thm.trim_context induct, |
|
139 |
mutual_induct = Thm.trim_context @{thm TrueI}, (*No need for mutual induction*) |
|
140 |
exhaustion = Thm.trim_context elim}; |
|
6070 | 141 |
|
142 |
val con_info = |
|
12175 | 143 |
{big_rec_name = big_rec_name, |
144 |
constructors = constructors, |
|
145 |
(*let primrec handle definition by cases*) |
|
146 |
free_iffs = [], (*thus we expect the necessary freeness rewrites |
|
147 |
to be in the simpset already, as is the case for |
|
148 |
Nat and disjoint sum*) |
|
70474 | 149 |
rec_rewrites = |
150 |
(case recursor_eqns of [] => case_eqns | _ => recursor_eqns) |
|
151 |
|> map Thm.trim_context}; |
|
6070 | 152 |
|
153 |
(*associate with each constructor the datatype name and rewrites*) |
|
154 |
val con_pairs = map (fn c => (#1 (dest_Const c), con_info)) constructors |
|
155 |
||
156 |
in |
|
17223 | 157 |
thy |
30364
577edc39b501
moved basic algebra of long names from structure NameSpace to Long_Name;
wenzelm
parents:
30280
diff
changeset
|
158 |
|> Sign.add_path (Long_Name.base_name big_rec_name) |
39557
fe5722fce758
renamed structure PureThy to Pure_Thy and moved most content to Global_Theory, to emphasize that this is global-only;
wenzelm
parents:
38522
diff
changeset
|
159 |
|> Global_Theory.add_thmss [((Binding.name "simps", simps), [Simplifier.simp_add])] |> snd |
78022 | 160 |
|> DatatypesData.map (Symtab.update (big_rec_name, dt_info)) |
161 |
|> ConstructorsData.map (fold_rev Symtab.update con_pairs) |
|
24712
64ed05609568
proper Sign operations instead of Theory aliases;
wenzelm
parents:
22846
diff
changeset
|
162 |
|> Sign.parent_path |
12204 | 163 |
end; |
6065 | 164 |
|
12204 | 165 |
fun rep_datatype raw_elim raw_induct raw_case_eqns raw_recursor_eqns thy = |
24725 | 166 |
let |
42361 | 167 |
val ctxt = Proof_Context.init_global thy; |
55740 | 168 |
val elim = Facts.the_single ("elimination", Position.none) (Attrib.eval_thms ctxt [raw_elim]); |
169 |
val induct = Facts.the_single ("induction", Position.none) (Attrib.eval_thms ctxt [raw_induct]); |
|
24725 | 170 |
val case_eqns = Attrib.eval_thms ctxt raw_case_eqns; |
171 |
val recursor_eqns = Attrib.eval_thms ctxt raw_recursor_eqns; |
|
172 |
in rep_datatype_i elim induct case_eqns recursor_eqns thy end; |
|
12175 | 173 |
|
12204 | 174 |
|
175 |
(* theory setup *) |
|
176 |
||
58828 | 177 |
val _ = |
178 |
Theory.setup |
|
69593 | 179 |
(Method.setup \<^binding>\<open>induct_tac\<close> |
74563 | 180 |
(Args.goal_spec -- Scan.lift (Parse.embedded -- Parse.for_fixes) >> |
59788 | 181 |
(fn (quant, (s, xs)) => fn ctxt => SIMPLE_METHOD'' quant (induct_tac ctxt s xs))) |
58828 | 182 |
"induct_tac emulation (dynamic instantiation!)" #> |
69593 | 183 |
Method.setup \<^binding>\<open>case_tac\<close> |
74563 | 184 |
(Args.goal_spec -- Scan.lift (Parse.embedded -- Parse.for_fixes) >> |
59788 | 185 |
(fn (quant, (s, xs)) => fn ctxt => SIMPLE_METHOD'' quant (exhaust_tac ctxt s xs))) |
58828 | 186 |
"datatype case_tac emulation (dynamic instantiation!)"); |
12204 | 187 |
|
188 |
||
189 |
(* outer syntax *) |
|
190 |
||
24867 | 191 |
val _ = |
69593 | 192 |
Outer_Syntax.command \<^command_keyword>\<open>rep_datatype\<close> "represent existing set inductively" |
193 |
((\<^keyword>\<open>elimination\<close> |-- Parse.!!! Parse.thm) -- |
|
194 |
(\<^keyword>\<open>induction\<close> |-- Parse.!!! Parse.thm) -- |
|
195 |
(\<^keyword>\<open>case_eqns\<close> |-- Parse.!!! Parse.thms1) -- |
|
196 |
Scan.optional (\<^keyword>\<open>recursor_eqns\<close> |-- Parse.!!! Parse.thms1) [] |
|
46961
5c6955f487e5
outer syntax command definitions based on formal command_spec derived from theory header declarations;
wenzelm
parents:
46949
diff
changeset
|
197 |
>> (fn (((x, y), z), w) => Toplevel.theory (rep_datatype x y z w))); |
12204 | 198 |
|
199 |
end; |
|
200 |
||
201 |
val exhaust_tac = DatatypeTactics.exhaust_tac; |
|
202 |
val induct_tac = DatatypeTactics.induct_tac; |