40 val induct_pred: string -> attribute |
42 val induct_pred: string -> attribute |
41 val induct_del: attribute |
43 val induct_del: attribute |
42 val coinduct_type: string -> attribute |
44 val coinduct_type: string -> attribute |
43 val coinduct_pred: string -> attribute |
45 val coinduct_pred: string -> attribute |
44 val coinduct_del: attribute |
46 val coinduct_del: attribute |
|
47 val map_simpset: (simpset -> simpset) -> Context.generic -> Context.generic |
|
48 val add_simp_rule: attribute |
|
49 val no_simpN: string |
45 val casesN: string |
50 val casesN: string |
46 val inductN: string |
51 val inductN: string |
47 val coinductN: string |
52 val coinductN: string |
48 val typeN: string |
53 val typeN: string |
49 val predN: string |
54 val predN: string |
50 val setN: string |
55 val setN: string |
51 (*proof methods*) |
56 (*proof methods*) |
52 val fix_tac: Proof.context -> int -> (string * typ) list -> int -> tactic |
57 val fix_tac: Proof.context -> int -> (string * typ) list -> int -> tactic |
53 val add_defs: (binding option * term) option list -> Proof.context -> |
58 val add_defs: (binding option * (term * bool)) option list -> Proof.context -> |
54 (term option list * thm list) * Proof.context |
59 (term option list * thm list) * Proof.context |
55 val atomize_term: theory -> term -> term |
60 val atomize_term: theory -> term -> term |
|
61 val atomize_cterm: conv |
56 val atomize_tac: int -> tactic |
62 val atomize_tac: int -> tactic |
57 val inner_atomize_tac: int -> tactic |
63 val inner_atomize_tac: int -> tactic |
58 val rulified_term: thm -> theory * term |
64 val rulified_term: thm -> theory * term |
59 val rulify_tac: int -> tactic |
65 val rulify_tac: int -> tactic |
|
66 val simplified_rule: Proof.context -> thm -> thm |
|
67 val simplify_tac: Proof.context -> int -> tactic |
|
68 val trivial_tac: int -> tactic |
|
69 val rotate_tac: int -> int -> int -> tactic |
60 val internalize: int -> thm -> thm |
70 val internalize: int -> thm -> thm |
61 val guess_instance: Proof.context -> thm -> int -> thm -> thm Seq.seq |
71 val guess_instance: Proof.context -> thm -> int -> thm -> thm Seq.seq |
62 val cases_tac: Proof.context -> term option list list -> thm option -> |
72 val cases_tac: Proof.context -> term option list list -> thm option -> |
63 thm list -> int -> cases_tactic |
73 thm list -> int -> cases_tactic |
64 val get_inductT: Proof.context -> term option list list -> thm list list |
74 val get_inductT: Proof.context -> term option list list -> thm list list |
65 val induct_tac: Proof.context -> (binding option * term) option list list -> |
75 val induct_tac: Proof.context -> bool -> (binding option * (term * bool)) option list list -> |
66 (string * typ) list list -> term option list -> thm list option -> |
76 (string * typ) list list -> term option list -> thm list option -> |
67 thm list -> int -> cases_tactic |
77 thm list -> int -> cases_tactic |
68 val coinduct_tac: Proof.context -> term option list -> term option list -> thm option -> |
78 val coinduct_tac: Proof.context -> term option list -> term option list -> thm option -> |
69 thm list -> int -> cases_tactic |
79 thm list -> int -> cases_tactic |
70 val setup: theory -> theory |
80 val setup: theory -> theory |
105 |
115 |
106 end; |
116 end; |
107 |
117 |
108 |
118 |
109 |
119 |
|
120 (** constraint simplification **) |
|
121 |
|
122 (* rearrange parameters and premises to allow application of one-point-rules *) |
|
123 |
|
124 fun swap_params_conv ctxt i j cv = |
|
125 let |
|
126 fun conv1 0 ctxt = Conv.forall_conv (cv o snd) ctxt |
|
127 | conv1 k ctxt = |
|
128 Conv.rewr_conv @{thm swap_params} then_conv |
|
129 Conv.forall_conv (conv1 (k-1) o snd) ctxt |
|
130 fun conv2 0 ctxt = conv1 j ctxt |
|
131 | conv2 k ctxt = Conv.forall_conv (conv2 (k-1) o snd) ctxt |
|
132 in conv2 i ctxt end; |
|
133 |
|
134 fun swap_prems_conv 0 = Conv.all_conv |
|
135 | swap_prems_conv i = |
|
136 Conv.implies_concl_conv (swap_prems_conv (i-1)) then_conv |
|
137 Conv.rewr_conv Drule.swap_prems_eq |
|
138 |
|
139 fun drop_judgment ctxt = ObjectLogic.drop_judgment (ProofContext.theory_of ctxt); |
|
140 |
|
141 fun find_eq ctxt t = |
|
142 let |
|
143 val l = length (Logic.strip_params t); |
|
144 val Hs = Logic.strip_assums_hyp t; |
|
145 fun find (i, t) = |
|
146 case Data.dest_def (drop_judgment ctxt t) of |
|
147 SOME (Bound j, _) => SOME (i, j) |
|
148 | SOME (_, Bound j) => SOME (i, j) |
|
149 | _ => NONE |
|
150 in |
|
151 case get_first find (map_index I Hs) of |
|
152 NONE => NONE |
|
153 | SOME (0, 0) => NONE |
|
154 | SOME (i, j) => SOME (i, l-j-1, j) |
|
155 end; |
|
156 |
|
157 fun mk_swap_rrule ctxt ct = case find_eq ctxt (term_of ct) of |
|
158 NONE => NONE |
|
159 | SOME (i, k, j) => SOME (swap_params_conv ctxt k j (K (swap_prems_conv i)) ct); |
|
160 |
|
161 val rearrange_eqs_simproc = Simplifier.simproc |
|
162 (Thm.theory_of_thm Drule.swap_prems_eq) "rearrange_eqs" ["all t"] |
|
163 (fn thy => fn ss => fn t => |
|
164 mk_swap_rrule (Simplifier.the_context ss) (cterm_of thy t)) |
|
165 |
|
166 (* rotate k premises to the left by j, skipping over first j premises *) |
|
167 |
|
168 fun rotate_conv 0 j 0 = Conv.all_conv |
|
169 | rotate_conv 0 j k = swap_prems_conv j then_conv rotate_conv 1 j (k-1) |
|
170 | rotate_conv i j k = Conv.implies_concl_conv (rotate_conv (i-1) j k); |
|
171 |
|
172 fun rotate_tac j 0 = K all_tac |
|
173 | rotate_tac j k = SUBGOAL (fn (goal, i) => CONVERSION (rotate_conv |
|
174 j (length (Logic.strip_assums_hyp goal) - j - k) k) i); |
|
175 |
|
176 (* rulify operators around definition *) |
|
177 |
|
178 fun rulify_defs_conv ctxt ct = |
|
179 if exists_subterm (is_some o Data.dest_def) (term_of ct) andalso |
|
180 not (is_some (Data.dest_def (drop_judgment ctxt (term_of ct)))) |
|
181 then |
|
182 (Conv.forall_conv (rulify_defs_conv o snd) ctxt else_conv |
|
183 Conv.implies_conv (Conv.try_conv (rulify_defs_conv ctxt)) |
|
184 (Conv.try_conv (rulify_defs_conv ctxt)) else_conv |
|
185 Conv.first_conv (map Conv.rewr_conv Data.rulify) then_conv |
|
186 Conv.try_conv (rulify_defs_conv ctxt)) ct |
|
187 else Conv.no_conv ct; |
|
188 |
|
189 |
|
190 |
110 (** induct data **) |
191 (** induct data **) |
111 |
192 |
112 (* rules *) |
193 (* rules *) |
113 |
194 |
114 type rules = (string * thm) Item_Net.T; |
195 type rules = (string * thm) Item_Net.T; |
130 |
211 |
131 (* context data *) |
212 (* context data *) |
132 |
213 |
133 structure InductData = Generic_Data |
214 structure InductData = Generic_Data |
134 ( |
215 ( |
135 type T = (rules * rules) * (rules * rules) * (rules * rules); |
216 type T = (rules * rules) * (rules * rules) * (rules * rules) * simpset; |
136 val empty = |
217 val empty = |
137 ((init_rules (left_var_prem o #2), init_rules (Thm.major_prem_of o #2)), |
218 ((init_rules (left_var_prem o #2), init_rules (Thm.major_prem_of o #2)), |
138 (init_rules (right_var_concl o #2), init_rules (Thm.major_prem_of o #2)), |
219 (init_rules (right_var_concl o #2), init_rules (Thm.major_prem_of o #2)), |
139 (init_rules (left_var_concl o #2), init_rules (Thm.concl_of o #2))); |
220 (init_rules (left_var_concl o #2), init_rules (Thm.concl_of o #2)), |
|
221 empty_ss addsimprocs [rearrange_eqs_simproc] addsimps [Drule.norm_hhf_eq]); |
140 val extend = I; |
222 val extend = I; |
141 fun merge (((casesT1, casesP1), (inductT1, inductP1), (coinductT1, coinductP1)), |
223 fun merge (((casesT1, casesP1), (inductT1, inductP1), (coinductT1, coinductP1), simpset1), |
142 ((casesT2, casesP2), (inductT2, inductP2), (coinductT2, coinductP2))) = |
224 ((casesT2, casesP2), (inductT2, inductP2), (coinductT2, coinductP2), simpset2)) = |
143 ((Item_Net.merge (casesT1, casesT2), Item_Net.merge (casesP1, casesP2)), |
225 ((Item_Net.merge (casesT1, casesT2), Item_Net.merge (casesP1, casesP2)), |
144 (Item_Net.merge (inductT1, inductT2), Item_Net.merge (inductP1, inductP2)), |
226 (Item_Net.merge (inductT1, inductT2), Item_Net.merge (inductP1, inductP2)), |
145 (Item_Net.merge (coinductT1, coinductT2), Item_Net.merge (coinductP1, coinductP2))); |
227 (Item_Net.merge (coinductT1, coinductT2), Item_Net.merge (coinductP1, coinductP2)), |
|
228 merge_ss (simpset1, simpset2)); |
146 ); |
229 ); |
147 |
230 |
148 val get_local = InductData.get o Context.Proof; |
231 val get_local = InductData.get o Context.Proof; |
149 |
232 |
150 fun dest_rules ctxt = |
233 fun dest_rules ctxt = |
151 let val ((casesT, casesP), (inductT, inductP), (coinductT, coinductP)) = get_local ctxt in |
234 let val ((casesT, casesP), (inductT, inductP), (coinductT, coinductP), _) = get_local ctxt in |
152 {type_cases = Item_Net.content casesT, |
235 {type_cases = Item_Net.content casesT, |
153 pred_cases = Item_Net.content casesP, |
236 pred_cases = Item_Net.content casesP, |
154 type_induct = Item_Net.content inductT, |
237 type_induct = Item_Net.content inductT, |
155 pred_induct = Item_Net.content inductP, |
238 pred_induct = Item_Net.content inductP, |
156 type_coinduct = Item_Net.content coinductT, |
239 type_coinduct = Item_Net.content coinductT, |
157 pred_coinduct = Item_Net.content coinductP} |
240 pred_coinduct = Item_Net.content coinductP} |
158 end; |
241 end; |
159 |
242 |
160 fun print_rules ctxt = |
243 fun print_rules ctxt = |
161 let val ((casesT, casesP), (inductT, inductP), (coinductT, coinductP)) = get_local ctxt in |
244 let val ((casesT, casesP), (inductT, inductP), (coinductT, coinductP), _) = get_local ctxt in |
162 [pretty_rules ctxt "coinduct type:" coinductT, |
245 [pretty_rules ctxt "coinduct type:" coinductT, |
163 pretty_rules ctxt "coinduct pred:" coinductP, |
246 pretty_rules ctxt "coinduct pred:" coinductP, |
164 pretty_rules ctxt "induct type:" inductT, |
247 pretty_rules ctxt "induct type:" inductT, |
165 pretty_rules ctxt "induct pred:" inductP, |
248 pretty_rules ctxt "induct pred:" inductP, |
166 pretty_rules ctxt "cases type:" casesT, |
249 pretty_rules ctxt "cases type:" casesT, |
204 let val (x, thm) = g arg in (InductData.map (f (name, thm)) x, thm) end; |
287 let val (x, thm) = g arg in (InductData.map (f (name, thm)) x, thm) end; |
205 |
288 |
206 fun del_att which = Thm.declaration_attribute (fn th => InductData.map (which (pairself (fn rs => |
289 fun del_att which = Thm.declaration_attribute (fn th => InductData.map (which (pairself (fn rs => |
207 fold Item_Net.remove (filter_rules rs th) rs)))); |
290 fold Item_Net.remove (filter_rules rs th) rs)))); |
208 |
291 |
209 fun map1 f (x, y, z) = (f x, y, z); |
292 fun map1 f (x, y, z, s) = (f x, y, z, s); |
210 fun map2 f (x, y, z) = (x, f y, z); |
293 fun map2 f (x, y, z, s) = (x, f y, z, s); |
211 fun map3 f (x, y, z) = (x, y, f z); |
294 fun map3 f (x, y, z, s) = (x, y, f z, s); |
|
295 fun map4 f (x, y, z, s) = (x, y, z, f s); |
212 |
296 |
213 fun add_casesT rule x = map1 (apfst (Item_Net.update rule)) x; |
297 fun add_casesT rule x = map1 (apfst (Item_Net.update rule)) x; |
214 fun add_casesP rule x = map1 (apsnd (Item_Net.update rule)) x; |
298 fun add_casesP rule x = map1 (apsnd (Item_Net.update rule)) x; |
215 fun add_inductT rule x = map2 (apfst (Item_Net.update rule)) x; |
299 fun add_inductT rule x = map2 (apfst (Item_Net.update rule)) x; |
216 fun add_inductP rule x = map2 (apsnd (Item_Net.update rule)) x; |
300 fun add_inductP rule x = map2 (apsnd (Item_Net.update rule)) x; |
546 |
654 |
547 (* add_defs *) |
655 (* add_defs *) |
548 |
656 |
549 fun add_defs def_insts = |
657 fun add_defs def_insts = |
550 let |
658 let |
551 fun add (SOME (SOME x, t)) ctxt = |
659 fun add (SOME (_, (t, true))) ctxt = ((SOME t, []), ctxt) |
|
660 | add (SOME (SOME x, (t, _))) ctxt = |
552 let val ([(lhs, (_, th))], ctxt') = |
661 let val ([(lhs, (_, th))], ctxt') = |
553 LocalDefs.add_defs [((x, NoSyn), (Thm.empty_binding, t))] ctxt |
662 LocalDefs.add_defs [((x, NoSyn), (Thm.empty_binding, t))] ctxt |
554 in ((SOME lhs, [th]), ctxt') end |
663 in ((SOME lhs, [th]), ctxt') end |
555 | add (SOME (NONE, t)) ctxt = ((SOME t, []), ctxt) |
664 | add (SOME (NONE, (t as Free _, _))) ctxt = ((SOME t, []), ctxt) |
|
665 | add (SOME (NONE, (t, _))) ctxt = |
|
666 let |
|
667 val ([s], _) = Name.variants ["x"] (Variable.names_of ctxt); |
|
668 val ([(lhs, (_, th))], ctxt') = |
|
669 LocalDefs.add_defs [((Binding.name s, NoSyn), |
|
670 (Thm.empty_binding, t))] ctxt |
|
671 in ((SOME lhs, [th]), ctxt') end |
556 | add NONE ctxt = ((NONE, []), ctxt); |
672 | add NONE ctxt = ((NONE, []), ctxt); |
557 in fold_map add def_insts #> apfst (split_list #> apsnd flat) end; |
673 in fold_map add def_insts #> apfst (split_list #> apsnd flat) end; |
558 |
674 |
559 |
675 |
560 (* induct_tac *) |
676 (* induct_tac *) |
574 |> filter_out (forall Rule_Cases.is_inner_rule); |
690 |> filter_out (forall Rule_Cases.is_inner_rule); |
575 |
691 |
576 fun get_inductP ctxt (fact :: _) = map single (find_inductP ctxt (Thm.concl_of fact)) |
692 fun get_inductP ctxt (fact :: _) = map single (find_inductP ctxt (Thm.concl_of fact)) |
577 | get_inductP _ _ = []; |
693 | get_inductP _ _ = []; |
578 |
694 |
579 fun induct_tac ctxt def_insts arbitrary taking opt_rule facts = |
695 fun induct_tac ctxt simp def_insts arbitrary taking opt_rule facts = |
580 let |
696 let |
581 val thy = ProofContext.theory_of ctxt; |
697 val thy = ProofContext.theory_of ctxt; |
582 |
698 |
583 val ((insts, defs), defs_ctxt) = fold_map add_defs def_insts ctxt |>> split_list; |
699 val ((insts, defs), defs_ctxt) = fold_map add_defs def_insts ctxt |>> split_list; |
584 val atomized_defs = map (map (Conv.fconv_rule ObjectLogic.atomize)) defs; |
700 val atomized_defs = map (map (Conv.fconv_rule atomize_cterm)) defs; |
585 |
701 |
586 fun inst_rule (concls, r) = |
702 fun inst_rule (concls, r) = |
587 (if null insts then `Rule_Cases.get r |
703 (if null insts then `Rule_Cases.get r |
588 else (align_left "Rule has fewer conclusions than arguments given" |
704 else (align_left "Rule has fewer conclusions than arguments given" |
589 (map Logic.strip_imp_concl (Logic.dest_conjunctions (Thm.concl_of r))) insts |
705 (map Logic.strip_imp_concl (Logic.dest_conjunctions (Thm.concl_of r))) insts |
599 map (special_rename_params defs_ctxt insts) (get_inductT ctxt insts)) |
715 map (special_rename_params defs_ctxt insts) (get_inductT ctxt insts)) |
600 |> map_filter (Rule_Cases.mutual_rule ctxt) |
716 |> map_filter (Rule_Cases.mutual_rule ctxt) |
601 |> tap (trace_rules ctxt inductN o map #2) |
717 |> tap (trace_rules ctxt inductN o map #2) |
602 |> Seq.of_list |> Seq.maps (Seq.try inst_rule)); |
718 |> Seq.of_list |> Seq.maps (Seq.try inst_rule)); |
603 |
719 |
604 fun rule_cases rule = |
720 fun rule_cases ctxt rule = |
605 Rule_Cases.make_nested false (Thm.prop_of rule) (rulified_term rule); |
721 let val rule' = (if simp then simplified_rule ctxt else I) |
|
722 (Rule_Cases.internalize_params rule); |
|
723 in Rule_Cases.make_nested (Thm.prop_of rule') (rulified_term rule') end; |
606 in |
724 in |
607 (fn i => fn st => |
725 (fn i => fn st => |
608 ruleq |
726 ruleq |
609 |> Seq.maps (Rule_Cases.consume (flat defs) facts) |
727 |> Seq.maps (Rule_Cases.consume (flat defs) facts) |
610 |> Seq.maps (fn (((cases, concls), (more_consumes, more_facts)), rule) => |
728 |> Seq.maps (fn (((cases, concls), (more_consumes, more_facts)), rule) => |
611 (PRECISE_CONJUNCTS (length concls) (ALLGOALS (fn j => |
729 (PRECISE_CONJUNCTS (length concls) (ALLGOALS (fn j => |
612 (CONJUNCTS (ALLGOALS |
730 (CONJUNCTS (ALLGOALS |
613 (Method.insert_tac (more_facts @ nth_list atomized_defs (j - 1)) |
731 let |
614 THEN' fix_tac defs_ctxt |
732 val adefs = nth_list atomized_defs (j - 1); |
615 (nth concls (j - 1) + more_consumes) |
733 val frees = fold (Term.add_frees o prop_of) adefs []; |
616 (nth_list arbitrary (j - 1)))) |
734 val xs = nth_list arbitrary (j - 1); |
|
735 val k = nth concls (j - 1) + more_consumes |
|
736 in |
|
737 Method.insert_tac (more_facts @ adefs) THEN' |
|
738 (if simp then |
|
739 rotate_tac k (length adefs) THEN' |
|
740 fix_tac defs_ctxt k |
|
741 (List.partition (member op = frees) xs |> op @) |
|
742 else |
|
743 fix_tac defs_ctxt k xs) |
|
744 end) |
617 THEN' inner_atomize_tac) j)) |
745 THEN' inner_atomize_tac) j)) |
618 THEN' atomize_tac) i st |> Seq.maps (fn st' => |
746 THEN' atomize_tac) i st |> Seq.maps (fn st' => |
619 guess_instance ctxt (internalize more_consumes rule) i st' |
747 guess_instance ctxt (internalize more_consumes rule) i st' |
620 |> Seq.map (rule_instance ctxt (burrow_options (Variable.polymorphic ctxt) taking)) |
748 |> Seq.map (rule_instance ctxt (burrow_options (Variable.polymorphic ctxt) taking)) |
621 |> Seq.maps (fn rule' => |
749 |> Seq.maps (fn rule' => |
622 CASES (rule_cases rule' cases) |
750 CASES (rule_cases ctxt rule' cases) |
623 (Tactic.rtac rule' i THEN |
751 (Tactic.rtac rule' i THEN |
624 PRIMITIVE (singleton (ProofContext.export defs_ctxt ctxt))) st')))) |
752 PRIMITIVE (singleton (ProofContext.export defs_ctxt ctxt))) st')))) |
625 THEN_ALL_NEW_CASES rulify_tac |
753 THEN_ALL_NEW_CASES |
|
754 ((if simp then simplify_tac ctxt THEN' (TRY o trivial_tac) |
|
755 else K all_tac) |
|
756 THEN_ALL_NEW rulify_tac) |
626 end; |
757 end; |
627 |
758 |
628 |
759 |
629 |
760 |
630 (** coinduct method **) |
761 (** coinduct method **) |
709 val induct_rule = rule lookup_inductT lookup_inductP; |
841 val induct_rule = rule lookup_inductT lookup_inductP; |
710 val coinduct_rule = rule lookup_coinductT lookup_coinductP >> single_rule; |
842 val coinduct_rule = rule lookup_coinductT lookup_coinductP >> single_rule; |
711 |
843 |
712 val inst = Scan.lift (Args.$$$ "_") >> K NONE || Args.term >> SOME; |
844 val inst = Scan.lift (Args.$$$ "_") >> K NONE || Args.term >> SOME; |
713 |
845 |
|
846 val inst' = Scan.lift (Args.$$$ "_") >> K NONE || |
|
847 Args.term >> (SOME o rpair false) || |
|
848 Scan.lift (Args.$$$ "(") |-- (Args.term >> (SOME o rpair true)) --| |
|
849 Scan.lift (Args.$$$ ")"); |
|
850 |
714 val def_inst = |
851 val def_inst = |
715 ((Scan.lift (Args.binding --| (Args.$$$ "\<equiv>" || Args.$$$ "==")) >> SOME) |
852 ((Scan.lift (Args.binding --| (Args.$$$ "\<equiv>" || Args.$$$ "==")) >> SOME) |
716 -- Args.term) >> SOME || |
853 -- (Args.term >> rpair false)) >> SOME || |
717 inst >> Option.map (pair NONE); |
854 inst' >> Option.map (pair NONE); |
718 |
855 |
719 val free = Args.context -- Args.term >> (fn (_, Free v) => v | (ctxt, t) => |
856 val free = Args.context -- Args.term >> (fn (_, Free v) => v | (ctxt, t) => |
720 error ("Bad free variable: " ^ Syntax.string_of_term ctxt t)); |
857 error ("Bad free variable: " ^ Syntax.string_of_term ctxt t)); |
721 |
858 |
722 fun unless_more_args scan = Scan.unless (Scan.lift |
859 fun unless_more_args scan = Scan.unless (Scan.lift |
738 METHOD_CASES (fn facts => Seq.DETERM (HEADGOAL (cases_tac ctxt insts opt_rule facts))))) |
875 METHOD_CASES (fn facts => Seq.DETERM (HEADGOAL (cases_tac ctxt insts opt_rule facts))))) |
739 "case analysis on types or predicates/sets"; |
876 "case analysis on types or predicates/sets"; |
740 |
877 |
741 val induct_setup = |
878 val induct_setup = |
742 Method.setup @{binding induct} |
879 Method.setup @{binding induct} |
743 (P.and_list' (Scan.repeat (unless_more_args def_inst)) -- |
880 (Args.mode no_simpN -- (P.and_list' (Scan.repeat (unless_more_args def_inst)) -- |
744 (arbitrary -- taking -- Scan.option induct_rule) >> |
881 (arbitrary -- taking -- Scan.option induct_rule)) >> |
745 (fn (insts, ((arbitrary, taking), opt_rule)) => fn ctxt => |
882 (fn (no_simp, (insts, ((arbitrary, taking), opt_rule))) => fn ctxt => |
746 RAW_METHOD_CASES (fn facts => |
883 RAW_METHOD_CASES (fn facts => |
747 Seq.DETERM (HEADGOAL (induct_tac ctxt insts arbitrary taking opt_rule facts))))) |
884 Seq.DETERM (HEADGOAL (induct_tac ctxt (not no_simp) insts arbitrary taking opt_rule facts))))) |
748 "induction on types or predicates/sets"; |
885 "induction on types or predicates/sets"; |
749 |
886 |
750 val coinduct_setup = |
887 val coinduct_setup = |
751 Method.setup @{binding coinduct} |
888 Method.setup @{binding coinduct} |
752 (Scan.repeat (unless_more_args inst) -- taking -- Scan.option coinduct_rule >> |
889 (Scan.repeat (unless_more_args inst) -- taking -- Scan.option coinduct_rule >> |