author | wenzelm |
Fri, 21 Oct 2016 21:03:17 +0200 | |
changeset 64340 | 7f42e66c0d3d |
parent 63120 | 629a4c5e953e |
child 67149 | e61557884799 |
permissions | -rw-r--r-- |
28308 | 1 |
(* Title: Tools/induct_tacs.ML |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
2 |
Author: Makarius |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
3 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
4 |
Unstructured induction and cases analysis. |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
5 |
*) |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
6 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
7 |
signature INDUCT_TACS = |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
8 |
sig |
59802 | 9 |
val case_tac: Proof.context -> string -> (binding * string option * mixfix) list -> |
59826 | 10 |
thm option -> int -> tactic |
11 |
val induct_tac: Proof.context -> string option list list -> |
|
12 |
thm list option -> int -> tactic |
|
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
13 |
end |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
14 |
|
45133 | 15 |
structure Induct_Tacs: INDUCT_TACS = |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
16 |
struct |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
17 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
18 |
(* case analysis *) |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
19 |
|
46836 | 20 |
fun check_type ctxt (t, pos) = |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
21 |
let |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
22 |
val u = singleton (Variable.polymorphic ctxt) t; |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
23 |
val U = Term.fastype_of u; |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
24 |
val _ = Term.is_TVar U andalso |
55715
bc04f1ab3c3a
tuned messages -- prefer quote before Position.here, which might be just \<here>;
wenzelm
parents:
55111
diff
changeset
|
25 |
error ("Cannot determine type of " ^ |
bc04f1ab3c3a
tuned messages -- prefer quote before Position.here, which might be just \<here>;
wenzelm
parents:
55111
diff
changeset
|
26 |
quote (Syntax.string_of_term ctxt u) ^ Position.here pos); |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
27 |
in (u, U) end; |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
28 |
|
59829 | 29 |
fun case_tac ctxt s fixes opt_rule = SUBGOAL (fn (goal, i) => |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
30 |
let |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
31 |
val rule = |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
32 |
(case opt_rule of |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
33 |
SOME rule => rule |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
34 |
| NONE => |
59802 | 35 |
let |
59827
04e569577c18
proper Rule_Insts.read_term, e.g. to enable case_tac using "_";
wenzelm
parents:
59826
diff
changeset
|
36 |
val (t, ctxt') = ctxt |
59829 | 37 |
|> Rule_Insts.goal_context goal |> #2 |
59827
04e569577c18
proper Rule_Insts.read_term, e.g. to enable case_tac using "_";
wenzelm
parents:
59826
diff
changeset
|
38 |
|> Context_Position.set_visible false |
04e569577c18
proper Rule_Insts.read_term, e.g. to enable case_tac using "_";
wenzelm
parents:
59826
diff
changeset
|
39 |
|> Rule_Insts.read_term s; |
04e569577c18
proper Rule_Insts.read_term, e.g. to enable case_tac using "_";
wenzelm
parents:
59826
diff
changeset
|
40 |
val pos = Syntax.read_input_pos s; |
59802 | 41 |
in |
59827
04e569577c18
proper Rule_Insts.read_term, e.g. to enable case_tac using "_";
wenzelm
parents:
59826
diff
changeset
|
42 |
(case Induct.find_casesT ctxt' (#2 (check_type ctxt' (t, pos))) of |
59802 | 43 |
rule :: _ => rule |
44 |
| [] => @{thm case_split}) |
|
45 |
end); |
|
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
46 |
val _ = Method.trace ctxt [rule]; |
59829 | 47 |
in |
48 |
(case Induct.vars_of (Thm.term_of (Thm.cprem_of rule 1)) handle THM _ => [] of |
|
49 |
Var (xi, _) :: _ => Rule_Insts.res_inst_tac ctxt [((xi, Position.none), s)] fixes rule i |
|
50 |
| _ => no_tac) |
|
51 |
end); |
|
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
52 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
53 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
54 |
(* induction *) |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
55 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
56 |
local |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
57 |
|
59755 | 58 |
fun prep_var (Var (xi, _), SOME x) = SOME ((xi, Position.none), x) |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
59 |
| prep_var _ = NONE; |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
60 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
61 |
fun prep_inst (concl, xs) = |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
62 |
let val vs = Induct.vars_of concl |
33957 | 63 |
in map_filter prep_var (drop (length vs - length xs) vs ~~ xs) end; |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
64 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
65 |
in |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
66 |
|
59830 | 67 |
fun induct_tac ctxt varss opt_rules i st = |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
68 |
let |
59830 | 69 |
val goal = Thm.cprem_of st i; |
70 |
val (_, goal_ctxt) = Rule_Insts.goal_context (Thm.term_of goal) ctxt |
|
60695
757549b4bbe6
Variable.focus etc.: optional bindings provided by user;
wenzelm
parents:
59830
diff
changeset
|
71 |
and ((_, goal'), _) = Variable.focus_cterm NONE goal ctxt; |
59830 | 72 |
val (prems, concl) = Logic.strip_horn (Thm.term_of goal'); |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
73 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
74 |
fun induct_var name = |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
75 |
let |
59830 | 76 |
val t = Syntax.read_term goal_ctxt name; |
59795 | 77 |
val pos = Syntax.read_input_pos name; |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
78 |
val (x, _) = Term.dest_Free t handle TERM _ => |
46836 | 79 |
error ("Induction argument not a variable: " ^ |
59830 | 80 |
quote (Syntax.string_of_term goal_ctxt t) ^ Position.here pos); |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
81 |
val eq_x = fn Free (y, _) => x = y | _ => false; |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
82 |
val _ = |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
83 |
if Term.exists_subterm eq_x concl then () |
46836 | 84 |
else |
85 |
error ("No such variable in subgoal: " ^ |
|
59830 | 86 |
quote (Syntax.string_of_term goal_ctxt t) ^ Position.here pos); |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
87 |
val _ = |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
88 |
if (exists o Term.exists_subterm) eq_x prems then |
46836 | 89 |
warning ("Induction variable occurs also among premises: " ^ |
59830 | 90 |
quote (Syntax.string_of_term goal_ctxt t) ^ Position.here pos) |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
91 |
else (); |
59830 | 92 |
in #1 (check_type goal_ctxt (t, pos)) end; |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
93 |
|
59830 | 94 |
val argss = (map o map o Option.map) induct_var varss; |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
95 |
val rule = |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
96 |
(case opt_rules of |
33368 | 97 |
SOME rules => #2 (Rule_Cases.strict_mutual_rule ctxt rules) |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
98 |
| NONE => |
33368 | 99 |
(case map_filter (Rule_Cases.mutual_rule ctxt) (Induct.get_inductT ctxt argss) of |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
100 |
(_, rule) :: _ => rule |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
101 |
| [] => raise THM ("No induction rules", 0, []))); |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
102 |
|
54742
7a86358a3c0b
proper context for basic Simplifier operations: rewrite_rule, rewrite_goals_rule, rewrite_goals_tac etc.;
wenzelm
parents:
48992
diff
changeset
|
103 |
val rule' = rule |> Conv.fconv_rule (Conv.concl_conv ~1 (Object_Logic.atomize ctxt)); |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
104 |
val _ = Method.trace ctxt [rule']; |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
105 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
106 |
val concls = Logic.dest_conjunctions (Thm.concl_of rule); |
40722
441260986b63
make two copies (!) of Library.UnequalLengths coincide with ListPair.UnequalLengths;
wenzelm
parents:
36960
diff
changeset
|
107 |
val insts = maps prep_inst (concls ~~ varss) handle ListPair.UnequalLengths => |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
108 |
error "Induction rule has different numbers of variables"; |
59780 | 109 |
in Rule_Insts.res_inst_tac ctxt insts [] rule' i st end |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
110 |
handle THM _ => Seq.empty; |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
111 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
112 |
end; |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
113 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
114 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
115 |
(* method syntax *) |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
116 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
117 |
local |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
118 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
119 |
val rule_spec = Scan.lift (Args.$$$ "rule" -- Args.$$$ ":"); |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
120 |
val opt_rule = Scan.option (rule_spec |-- Attrib.thm); |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
121 |
val opt_rules = Scan.option (rule_spec |-- Attrib.thms); |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
122 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
123 |
val varss = |
55111 | 124 |
Parse.and_list' |
63120
629a4c5e953e
embedded content may be delimited via cartouches;
wenzelm
parents:
60695
diff
changeset
|
125 |
(Scan.repeat (Scan.unless rule_spec (Scan.lift (Args.maybe Args.embedded_inner_syntax)))); |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
126 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
127 |
in |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
128 |
|
58826 | 129 |
val _ = |
130 |
Theory.setup |
|
131 |
(Method.setup @{binding case_tac} |
|
63120
629a4c5e953e
embedded content may be delimited via cartouches;
wenzelm
parents:
60695
diff
changeset
|
132 |
(Args.goal_spec -- Scan.lift (Args.embedded_inner_syntax -- Parse.for_fixes) -- opt_rule >> |
59826 | 133 |
(fn ((quant, (s, xs)), r) => fn ctxt => SIMPLE_METHOD'' quant (case_tac ctxt s xs r))) |
58826 | 134 |
"unstructured case analysis on types" #> |
135 |
Method.setup @{binding induct_tac} |
|
136 |
(Args.goal_spec -- varss -- opt_rules >> |
|
59826 | 137 |
(fn ((quant, vs), rs) => fn ctxt => SIMPLE_METHOD'' quant (induct_tac ctxt vs rs))) |
58826 | 138 |
"unstructured induction on types"); |
27326
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
139 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
140 |
end; |
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
141 |
|
d3beec370964
moved src/HOL/Tools/induct_tacs.ML to src/Tools/induct_tacs.ML;
wenzelm
parents:
diff
changeset
|
142 |
end; |