16 signature INDUCT = |
16 signature INDUCT = |
17 sig |
17 sig |
18 (*rule declarations*) |
18 (*rule declarations*) |
19 val vars_of: term -> term list |
19 val vars_of: term -> term list |
20 val dest_rules: Proof.context -> |
20 val dest_rules: Proof.context -> |
21 {type_cases: (string * thm) list, set_cases: (string * thm) list, |
21 {type_cases: (string * thm) list, pred_cases: (string * thm) list, |
22 type_induct: (string * thm) list, set_induct: (string * thm) list, |
22 type_induct: (string * thm) list, pred_induct: (string * thm) list, |
23 type_coinduct: (string * thm) list, set_coinduct: (string * thm) list} |
23 type_coinduct: (string * thm) list, pred_coinduct: (string * thm) list} |
24 val print_rules: Proof.context -> unit |
24 val print_rules: Proof.context -> unit |
25 val lookup_casesT: Proof.context -> string -> thm option |
25 val lookup_casesT: Proof.context -> string -> thm option |
26 val lookup_casesS: Proof.context -> string -> thm option |
26 val lookup_casesP: Proof.context -> string -> thm option |
27 val lookup_inductT: Proof.context -> string -> thm option |
27 val lookup_inductT: Proof.context -> string -> thm option |
28 val lookup_inductS: Proof.context -> string -> thm option |
28 val lookup_inductP: Proof.context -> string -> thm option |
29 val lookup_coinductT: Proof.context -> string -> thm option |
29 val lookup_coinductT: Proof.context -> string -> thm option |
30 val lookup_coinductS: Proof.context -> string -> thm option |
30 val lookup_coinductP: Proof.context -> string -> thm option |
31 val find_casesT: Proof.context -> typ -> thm list |
31 val find_casesT: Proof.context -> typ -> thm list |
32 val find_casesS: Proof.context -> term -> thm list |
32 val find_casesP: Proof.context -> term -> thm list |
33 val find_inductT: Proof.context -> typ -> thm list |
33 val find_inductT: Proof.context -> typ -> thm list |
34 val find_inductS: Proof.context -> term -> thm list |
34 val find_inductP: Proof.context -> term -> thm list |
35 val find_coinductT: Proof.context -> typ -> thm list |
35 val find_coinductT: Proof.context -> typ -> thm list |
36 val find_coinductS: Proof.context -> term -> thm list |
36 val find_coinductP: Proof.context -> term -> thm list |
37 val cases_type: string -> attribute |
37 val cases_type: string -> attribute |
38 val cases_set: string -> attribute |
38 val cases_pred: string -> attribute |
39 val induct_type: string -> attribute |
39 val induct_type: string -> attribute |
40 val induct_set: string -> attribute |
40 val induct_pred: string -> attribute |
41 val coinduct_type: string -> attribute |
41 val coinduct_type: string -> attribute |
42 val coinduct_set: string -> attribute |
42 val coinduct_pred: string -> attribute |
43 val casesN: string |
43 val casesN: string |
44 val inductN: string |
44 val inductN: string |
45 val coinductN: string |
45 val coinductN: string |
46 val typeN: string |
46 val typeN: string |
|
47 val predN: string |
47 val setN: string |
48 val setN: string |
48 (*proof methods*) |
49 (*proof methods*) |
49 val fix_tac: Proof.context -> int -> (string * typ) list -> int -> tactic |
50 val fix_tac: Proof.context -> int -> (string * typ) list -> int -> tactic |
50 val add_defs: (string option * term) option list -> Proof.context -> |
51 val add_defs: (string option * term) option list -> Proof.context -> |
51 (term option list * thm list) * Proof.context |
52 (term option list * thm list) * Proof.context |
128 val empty = |
129 val empty = |
129 ((init_rules (left_var_prem o #2), init_rules (Thm.major_prem_of o #2)), |
130 ((init_rules (left_var_prem o #2), init_rules (Thm.major_prem_of o #2)), |
130 (init_rules (right_var_concl o #2), init_rules (Thm.major_prem_of o #2)), |
131 (init_rules (right_var_concl o #2), init_rules (Thm.major_prem_of o #2)), |
131 (init_rules (left_var_concl o #2), init_rules (Thm.concl_of o #2))); |
132 (init_rules (left_var_concl o #2), init_rules (Thm.concl_of o #2))); |
132 val extend = I; |
133 val extend = I; |
133 fun merge _ (((casesT1, casesS1), (inductT1, inductS1), (coinductT1, coinductS1)), |
134 fun merge _ (((casesT1, casesP1), (inductT1, inductP1), (coinductT1, coinductP1)), |
134 ((casesT2, casesS2), (inductT2, inductS2), (coinductT2, coinductS2))) = |
135 ((casesT2, casesP2), (inductT2, inductP2), (coinductT2, coinductP2))) = |
135 ((NetRules.merge (casesT1, casesT2), NetRules.merge (casesS1, casesS2)), |
136 ((NetRules.merge (casesT1, casesT2), NetRules.merge (casesP1, casesP2)), |
136 (NetRules.merge (inductT1, inductT2), NetRules.merge (inductS1, inductS2)), |
137 (NetRules.merge (inductT1, inductT2), NetRules.merge (inductP1, inductP2)), |
137 (NetRules.merge (coinductT1, coinductT2), NetRules.merge (coinductS1, coinductS2))); |
138 (NetRules.merge (coinductT1, coinductT2), NetRules.merge (coinductP1, coinductP2))); |
138 ); |
139 ); |
139 |
140 |
140 val get_local = Induct.get o Context.Proof; |
141 val get_local = Induct.get o Context.Proof; |
141 |
142 |
142 fun dest_rules ctxt = |
143 fun dest_rules ctxt = |
143 let val ((casesT, casesS), (inductT, inductS), (coinductT, coinductS)) = get_local ctxt in |
144 let val ((casesT, casesP), (inductT, inductP), (coinductT, coinductP)) = get_local ctxt in |
144 {type_cases = NetRules.rules casesT, |
145 {type_cases = NetRules.rules casesT, |
145 set_cases = NetRules.rules casesS, |
146 pred_cases = NetRules.rules casesP, |
146 type_induct = NetRules.rules inductT, |
147 type_induct = NetRules.rules inductT, |
147 set_induct = NetRules.rules inductS, |
148 pred_induct = NetRules.rules inductP, |
148 type_coinduct = NetRules.rules coinductT, |
149 type_coinduct = NetRules.rules coinductT, |
149 set_coinduct = NetRules.rules coinductS} |
150 pred_coinduct = NetRules.rules coinductP} |
150 end; |
151 end; |
151 |
152 |
152 fun print_rules ctxt = |
153 fun print_rules ctxt = |
153 let val ((casesT, casesS), (inductT, inductS), (coinductT, coinductS)) = get_local ctxt in |
154 let val ((casesT, casesP), (inductT, inductP), (coinductT, coinductP)) = get_local ctxt in |
154 [pretty_rules ctxt "coinduct type:" coinductT, |
155 [pretty_rules ctxt "coinduct type:" coinductT, |
155 pretty_rules ctxt "coinduct set:" coinductS, |
156 pretty_rules ctxt "coinduct pred:" coinductP, |
156 pretty_rules ctxt "induct type:" inductT, |
157 pretty_rules ctxt "induct type:" inductT, |
157 pretty_rules ctxt "induct set:" inductS, |
158 pretty_rules ctxt "induct pred:" inductP, |
158 pretty_rules ctxt "cases type:" casesT, |
159 pretty_rules ctxt "cases type:" casesT, |
159 pretty_rules ctxt "cases set:" casesS] |
160 pretty_rules ctxt "cases pred:" casesP] |
160 |> Pretty.chunks |> Pretty.writeln |
161 |> Pretty.chunks |> Pretty.writeln |
161 end; |
162 end; |
162 |
163 |
163 val _ = OuterSyntax.add_parsers [ |
164 val _ = OuterSyntax.add_parsers [ |
164 OuterSyntax.improper_command "print_induct_rules" "print induction and cases rules" |
165 OuterSyntax.improper_command "print_induct_rules" "print induction and cases rules" |
167 |
168 |
168 |
169 |
169 (* access rules *) |
170 (* access rules *) |
170 |
171 |
171 val lookup_casesT = lookup_rule o #1 o #1 o get_local; |
172 val lookup_casesT = lookup_rule o #1 o #1 o get_local; |
172 val lookup_casesS = lookup_rule o #2 o #1 o get_local; |
173 val lookup_casesP = lookup_rule o #2 o #1 o get_local; |
173 val lookup_inductT = lookup_rule o #1 o #2 o get_local; |
174 val lookup_inductT = lookup_rule o #1 o #2 o get_local; |
174 val lookup_inductS = lookup_rule o #2 o #2 o get_local; |
175 val lookup_inductP = lookup_rule o #2 o #2 o get_local; |
175 val lookup_coinductT = lookup_rule o #1 o #3 o get_local; |
176 val lookup_coinductT = lookup_rule o #1 o #3 o get_local; |
176 val lookup_coinductS = lookup_rule o #2 o #3 o get_local; |
177 val lookup_coinductP = lookup_rule o #2 o #3 o get_local; |
177 |
178 |
178 |
179 |
179 fun find_rules which how ctxt x = |
180 fun find_rules which how ctxt x = |
180 map snd (NetRules.retrieve (which (get_local ctxt)) (how x)); |
181 map snd (NetRules.retrieve (which (get_local ctxt)) (how x)); |
181 |
182 |
182 val find_casesT = find_rules (#1 o #1) encode_type; |
183 val find_casesT = find_rules (#1 o #1) encode_type; |
183 val find_casesS = find_rules (#2 o #1) I; |
184 val find_casesP = find_rules (#2 o #1) I; |
184 val find_inductT = find_rules (#1 o #2) encode_type; |
185 val find_inductT = find_rules (#1 o #2) encode_type; |
185 val find_inductS = find_rules (#2 o #2) I; |
186 val find_inductP = find_rules (#2 o #2) I; |
186 val find_coinductT = find_rules (#1 o #3) encode_type; |
187 val find_coinductT = find_rules (#1 o #3) encode_type; |
187 val find_coinductS = find_rules (#2 o #3) I; |
188 val find_coinductP = find_rules (#2 o #3) I; |
188 |
189 |
189 |
190 |
190 |
191 |
191 (** attributes **) |
192 (** attributes **) |
192 |
193 |
198 fun map1 f (x, y, z) = (f x, y, z); |
199 fun map1 f (x, y, z) = (f x, y, z); |
199 fun map2 f (x, y, z) = (x, f y, z); |
200 fun map2 f (x, y, z) = (x, f y, z); |
200 fun map3 f (x, y, z) = (x, y, f z); |
201 fun map3 f (x, y, z) = (x, y, f z); |
201 |
202 |
202 fun add_casesT rule x = map1 (apfst (NetRules.insert rule)) x; |
203 fun add_casesT rule x = map1 (apfst (NetRules.insert rule)) x; |
203 fun add_casesS rule x = map1 (apsnd (NetRules.insert rule)) x; |
204 fun add_casesP rule x = map1 (apsnd (NetRules.insert rule)) x; |
204 fun add_inductT rule x = map2 (apfst (NetRules.insert rule)) x; |
205 fun add_inductT rule x = map2 (apfst (NetRules.insert rule)) x; |
205 fun add_inductS rule x = map2 (apsnd (NetRules.insert rule)) x; |
206 fun add_inductP rule x = map2 (apsnd (NetRules.insert rule)) x; |
206 fun add_coinductT rule x = map3 (apfst (NetRules.insert rule)) x; |
207 fun add_coinductT rule x = map3 (apfst (NetRules.insert rule)) x; |
207 fun add_coinductS rule x = map3 (apsnd (NetRules.insert rule)) x; |
208 fun add_coinductP rule x = map3 (apsnd (NetRules.insert rule)) x; |
208 |
209 |
209 fun consumes0 x = RuleCases.consumes_default 0 x; |
210 fun consumes0 x = RuleCases.consumes_default 0 x; |
210 fun consumes1 x = RuleCases.consumes_default 1 x; |
211 fun consumes1 x = RuleCases.consumes_default 1 x; |
211 |
212 |
212 in |
213 in |
213 |
214 |
214 val cases_type = mk_att add_casesT consumes0; |
215 val cases_type = mk_att add_casesT consumes0; |
215 val cases_set = mk_att add_casesS consumes1; |
216 val cases_pred = mk_att add_casesP consumes1; |
216 val induct_type = mk_att add_inductT consumes0; |
217 val induct_type = mk_att add_inductT consumes0; |
217 val induct_set = mk_att add_inductS consumes1; |
218 val induct_pred = mk_att add_inductP consumes1; |
218 val coinduct_type = mk_att add_coinductT consumes0; |
219 val coinduct_type = mk_att add_coinductT consumes0; |
219 val coinduct_set = mk_att add_coinductS consumes1; |
220 val coinduct_pred = mk_att add_coinductP consumes1; |
220 |
221 |
221 end; |
222 end; |
222 |
223 |
223 |
224 |
224 |
225 |
227 val casesN = "cases"; |
228 val casesN = "cases"; |
228 val inductN = "induct"; |
229 val inductN = "induct"; |
229 val coinductN = "coinduct"; |
230 val coinductN = "coinduct"; |
230 |
231 |
231 val typeN = "type"; |
232 val typeN = "type"; |
|
233 val predN = "pred"; |
232 val setN = "set"; |
234 val setN = "set"; |
233 |
235 |
234 local |
236 local |
235 |
237 |
236 fun spec k arg = |
238 fun spec k arg = |
237 Scan.lift (Args.$$$ k -- Args.colon) |-- arg || |
239 Scan.lift (Args.$$$ k -- Args.colon) |-- arg || |
238 Scan.lift (Args.$$$ k) >> K ""; |
240 Scan.lift (Args.$$$ k) >> K ""; |
239 |
241 |
240 fun attrib add_type add_set = |
242 fun attrib add_type add_pred = Attrib.syntax |
241 Attrib.syntax (spec typeN Args.tyname >> add_type || spec setN Args.const >> add_set); |
243 (spec typeN Args.tyname >> add_type || |
242 |
244 spec predN Args.const >> add_pred || |
243 val cases_att = attrib cases_type cases_set; |
245 spec setN Args.const >> add_pred); |
244 val induct_att = attrib induct_type induct_set; |
246 |
245 val coinduct_att = attrib coinduct_type coinduct_set; |
247 val cases_att = attrib cases_type cases_pred; |
|
248 val induct_att = attrib induct_type induct_pred; |
|
249 val coinduct_att = attrib coinduct_type coinduct_pred; |
246 |
250 |
247 in |
251 in |
248 |
252 |
249 val attrib_setup = Attrib.add_attributes |
253 val attrib_setup = Attrib.add_attributes |
250 [(casesN, cases_att, "declaration of cases rule for type or set"), |
254 [(casesN, cases_att, "declaration of cases rule for type or predicate/set"), |
251 (inductN, induct_att, "declaration of induction rule for type or set"), |
255 (inductN, induct_att, "declaration of induction rule for type or predicate/set"), |
252 (coinductN, coinduct_att, "declaration of coinduction rule for type or set")]; |
256 (coinductN, coinduct_att, "declaration of coinduction rule for type or predicate/set")]; |
253 |
257 |
254 end; |
258 end; |
255 |
259 |
256 |
260 |
257 |
261 |
647 val thy = ProofContext.theory_of ctxt; |
654 val thy = ProofContext.theory_of ctxt; |
648 val cert = Thm.cterm_of thy; |
655 val cert = Thm.cterm_of thy; |
649 |
656 |
650 fun inst_rule r = |
657 fun inst_rule r = |
651 if null inst then `RuleCases.get r |
658 if null inst then `RuleCases.get r |
652 else Drule.cterm_instantiate (prep_inst thy align_left I (Thm.concl_of r, inst)) r |
659 else Drule.cterm_instantiate (prep_inst thy align_right I (main_prop_of r, inst)) r |
653 |> pair (RuleCases.get r); |
660 |> pair (RuleCases.get r); |
654 |
661 |
655 fun ruleq goal = |
662 fun ruleq goal = |
656 (case opt_rule of |
663 (case opt_rule of |
657 SOME r => Seq.single (inst_rule r) |
664 SOME r => Seq.single (inst_rule r) |
658 | NONE => |
665 | NONE => |
659 (get_coinductS ctxt goal @ get_coinductT ctxt inst) |
666 (get_coinductP ctxt goal @ get_coinductT ctxt inst) |
660 |> tap (trace_rules ctxt coinductN) |
667 |> tap (trace_rules ctxt coinductN) |
661 |> Seq.of_list |> Seq.maps (Seq.try inst_rule)); |
668 |> Seq.of_list |> Seq.maps (Seq.try inst_rule)); |
662 in |
669 in |
663 SUBGOAL_CASES (fn (goal, i) => fn st => |
670 SUBGOAL_CASES (fn (goal, i) => fn st => |
664 ruleq goal |
671 ruleq goal |
691 Scan.lift (Args.$$$ k -- Args.colon) |-- Scan.repeat arg :|-- |
698 Scan.lift (Args.$$$ k -- Args.colon) |-- Scan.repeat arg :|-- |
692 (fn names => Scan.peek (fn context => Scan.succeed (names |> map (fn name => |
699 (fn names => Scan.peek (fn context => Scan.succeed (names |> map (fn name => |
693 (case get (Context.proof_of context) name of SOME x => x |
700 (case get (Context.proof_of context) name of SOME x => x |
694 | NONE => error ("No rule for " ^ k ^ " " ^ quote name)))))); |
701 | NONE => error ("No rule for " ^ k ^ " " ^ quote name)))))); |
695 |
702 |
696 fun rule get_type get_set = |
703 fun rule get_type get_pred = |
697 named_rule typeN Args.tyname get_type || |
704 named_rule typeN Args.tyname get_type || |
698 named_rule setN Args.const get_set || |
705 named_rule predN Args.const get_pred || |
|
706 named_rule setN Args.const get_pred || |
699 Scan.lift (Args.$$$ ruleN -- Args.colon) |-- Attrib.thms; |
707 Scan.lift (Args.$$$ ruleN -- Args.colon) |-- Attrib.thms; |
700 |
708 |
701 val cases_rule = rule lookup_casesT lookup_casesS >> single_rule; |
709 val cases_rule = rule lookup_casesT lookup_casesP >> single_rule; |
702 val induct_rule = rule lookup_inductT lookup_inductS; |
710 val induct_rule = rule lookup_inductT lookup_inductP; |
703 val coinduct_rule = rule lookup_coinductT lookup_coinductS >> single_rule; |
711 val coinduct_rule = rule lookup_coinductT lookup_coinductP >> single_rule; |
704 |
712 |
705 val inst = Scan.lift (Args.$$$ "_") >> K NONE || Args.term >> SOME; |
713 val inst = Scan.lift (Args.$$$ "_") >> K NONE || Args.term >> SOME; |
706 |
714 |
707 val def_inst = |
715 val def_inst = |
708 ((Scan.lift (Args.name --| (Args.$$$ "\\<equiv>" || Args.$$$ "==")) >> SOME) |
716 ((Scan.lift (Args.name --| (Args.$$$ "\\<equiv>" || Args.$$$ "==")) >> SOME) |
712 val free = Scan.state -- Args.term >> (fn (_, Free v) => v | (context, t) => |
720 val free = Scan.state -- Args.term >> (fn (_, Free v) => v | (context, t) => |
713 error ("Bad free variable: " ^ ProofContext.string_of_term (Context.proof_of context) t)); |
721 error ("Bad free variable: " ^ ProofContext.string_of_term (Context.proof_of context) t)); |
714 |
722 |
715 fun unless_more_args scan = Scan.unless (Scan.lift |
723 fun unless_more_args scan = Scan.unless (Scan.lift |
716 ((Args.$$$ arbitraryN || Args.$$$ takingN || Args.$$$ typeN || |
724 ((Args.$$$ arbitraryN || Args.$$$ takingN || Args.$$$ typeN || |
717 Args.$$$ setN || Args.$$$ ruleN) -- Args.colon)) scan; |
725 Args.$$$ predN || Args.$$$ setN || Args.$$$ ruleN) -- Args.colon)) scan; |
718 |
726 |
719 val arbitrary = Scan.optional (Scan.lift (Args.$$$ arbitraryN -- Args.colon) |-- |
727 val arbitrary = Scan.optional (Scan.lift (Args.$$$ arbitraryN -- Args.colon) |-- |
720 Args.and_list1 (Scan.repeat (unless_more_args free))) []; |
728 Args.and_list1 (Scan.repeat (unless_more_args free))) []; |
721 |
729 |
722 val taking = Scan.optional (Scan.lift (Args.$$$ takingN -- Args.colon) |-- |
730 val taking = Scan.optional (Scan.lift (Args.$$$ takingN -- Args.colon) |-- |