wenzelm@27326
|
1 |
(* Title: HOL/Tools/induct_tacs.ML
|
wenzelm@27326
|
2 |
ID: $Id$
|
wenzelm@27326
|
3 |
Author: Makarius
|
wenzelm@27326
|
4 |
|
wenzelm@27326
|
5 |
Unstructured induction and cases analysis.
|
wenzelm@27326
|
6 |
*)
|
wenzelm@27326
|
7 |
|
wenzelm@27326
|
8 |
signature INDUCT_TACS =
|
wenzelm@27326
|
9 |
sig
|
wenzelm@27326
|
10 |
val case_tac: Proof.context -> string -> int -> tactic
|
wenzelm@27326
|
11 |
val case_rule_tac: Proof.context -> string -> thm -> int -> tactic
|
wenzelm@27326
|
12 |
val induct_tac: Proof.context -> string option list list -> int -> tactic
|
wenzelm@27326
|
13 |
val induct_rules_tac: Proof.context -> string option list list -> thm list -> int -> tactic
|
wenzelm@27326
|
14 |
val setup: theory -> theory
|
wenzelm@27326
|
15 |
end
|
wenzelm@27326
|
16 |
|
wenzelm@27326
|
17 |
structure InductTacs: INDUCT_TACS =
|
wenzelm@27326
|
18 |
struct
|
wenzelm@27326
|
19 |
|
wenzelm@27326
|
20 |
(* case analysis *)
|
wenzelm@27326
|
21 |
|
wenzelm@27326
|
22 |
fun check_type ctxt t =
|
wenzelm@27326
|
23 |
let
|
wenzelm@27326
|
24 |
val u = singleton (Variable.polymorphic ctxt) t;
|
wenzelm@27326
|
25 |
val U = Term.fastype_of u;
|
wenzelm@27326
|
26 |
val _ = Term.is_TVar U andalso
|
wenzelm@27326
|
27 |
error ("Cannot determine type of " ^ Syntax.string_of_term ctxt u);
|
wenzelm@27326
|
28 |
in (u, U) end;
|
wenzelm@27326
|
29 |
|
wenzelm@27326
|
30 |
fun gen_case_tac ctxt0 (s, opt_rule) i st =
|
wenzelm@27326
|
31 |
let
|
wenzelm@27326
|
32 |
val ((_, goal), ctxt) = Variable.focus_subgoal i st ctxt0;
|
wenzelm@27326
|
33 |
val rule =
|
wenzelm@27326
|
34 |
(case opt_rule of
|
wenzelm@27326
|
35 |
SOME rule => rule
|
wenzelm@27326
|
36 |
| NONE =>
|
wenzelm@27326
|
37 |
(case Induct.find_casesT ctxt
|
wenzelm@27326
|
38 |
(#2 (check_type ctxt (ProofContext.read_term_schematic ctxt s))) of
|
wenzelm@27326
|
39 |
rule :: _ => rule
|
wenzelm@27326
|
40 |
| [] => @{thm case_split}));
|
wenzelm@27326
|
41 |
val _ = Method.trace ctxt [rule];
|
wenzelm@27326
|
42 |
|
wenzelm@27326
|
43 |
val xi =
|
wenzelm@27326
|
44 |
(case Induct.vars_of (Thm.term_of (Thm.cprem_of rule 1)) of
|
wenzelm@27326
|
45 |
Var (xi, _) :: _ => xi
|
wenzelm@27326
|
46 |
| _ => raise THM ("Malformed cases rule", 0, [rule]));
|
wenzelm@27326
|
47 |
in res_inst_tac ctxt [(xi, s)] rule i st end
|
wenzelm@27326
|
48 |
handle THM _ => Seq.empty;
|
wenzelm@27326
|
49 |
|
wenzelm@27326
|
50 |
fun case_tac ctxt s = gen_case_tac ctxt (s, NONE);
|
wenzelm@27326
|
51 |
fun case_rule_tac ctxt s rule = gen_case_tac ctxt (s, SOME rule);
|
wenzelm@27326
|
52 |
|
wenzelm@27326
|
53 |
|
wenzelm@27326
|
54 |
(* induction *)
|
wenzelm@27326
|
55 |
|
wenzelm@27326
|
56 |
local
|
wenzelm@27326
|
57 |
|
wenzelm@27326
|
58 |
fun prep_var (Var (ixn, _), SOME x) = SOME (ixn, x)
|
wenzelm@27326
|
59 |
| prep_var _ = NONE;
|
wenzelm@27326
|
60 |
|
wenzelm@27326
|
61 |
fun prep_inst (concl, xs) =
|
wenzelm@27326
|
62 |
let val vs = Induct.vars_of concl
|
wenzelm@27326
|
63 |
in map_filter prep_var (Library.drop (length vs - length xs, vs) ~~ xs) end;
|
wenzelm@27326
|
64 |
|
wenzelm@27326
|
65 |
in
|
wenzelm@27326
|
66 |
|
wenzelm@27326
|
67 |
fun gen_induct_tac ctxt0 (varss, opt_rules) i st =
|
wenzelm@27326
|
68 |
let
|
wenzelm@27326
|
69 |
val ((_, goal), ctxt) = Variable.focus_subgoal i st ctxt0;
|
wenzelm@27326
|
70 |
val (prems, concl) = Logic.strip_horn (Thm.term_of goal);
|
wenzelm@27326
|
71 |
|
wenzelm@27326
|
72 |
fun induct_var name =
|
wenzelm@27326
|
73 |
let
|
wenzelm@27326
|
74 |
val t = Syntax.read_term ctxt name;
|
wenzelm@27326
|
75 |
val (x, _) = Term.dest_Free t handle TERM _ =>
|
wenzelm@27326
|
76 |
error ("Induction argument not a variable: " ^ Syntax.string_of_term ctxt t);
|
wenzelm@27326
|
77 |
val eq_x = fn Free (y, _) => x = y | _ => false;
|
wenzelm@27326
|
78 |
val _ =
|
wenzelm@27326
|
79 |
if Term.exists_subterm eq_x concl then ()
|
wenzelm@27326
|
80 |
else error ("No such variable in subgoal: " ^ Syntax.string_of_term ctxt t);
|
wenzelm@27326
|
81 |
val _ =
|
wenzelm@27326
|
82 |
if (exists o Term.exists_subterm) eq_x prems then
|
wenzelm@27326
|
83 |
warning ("Induction variable occurs also among premises: " ^ Syntax.string_of_term ctxt t)
|
wenzelm@27326
|
84 |
else ();
|
wenzelm@27326
|
85 |
in #1 (check_type ctxt t) end;
|
wenzelm@27326
|
86 |
|
wenzelm@27326
|
87 |
val argss = map (map (Option.map induct_var)) varss;
|
wenzelm@27326
|
88 |
val rule =
|
wenzelm@27326
|
89 |
(case opt_rules of
|
wenzelm@27326
|
90 |
SOME rules => #2 (RuleCases.strict_mutual_rule ctxt rules)
|
wenzelm@27326
|
91 |
| NONE =>
|
wenzelm@27326
|
92 |
(case map_filter (RuleCases.mutual_rule ctxt) (Induct.get_inductT ctxt argss) of
|
wenzelm@27326
|
93 |
(_, rule) :: _ => rule
|
wenzelm@27326
|
94 |
| [] => raise THM ("No induction rules", 0, [])));
|
wenzelm@27326
|
95 |
|
wenzelm@27326
|
96 |
val rule' = rule |> Conv.fconv_rule (Conv.concl_conv ~1 ObjectLogic.atomize);
|
wenzelm@27326
|
97 |
val _ = Method.trace ctxt [rule'];
|
wenzelm@27326
|
98 |
|
wenzelm@27326
|
99 |
val concls = Logic.dest_conjunctions (Thm.concl_of rule);
|
wenzelm@27326
|
100 |
val insts = maps prep_inst (concls ~~ varss) handle Library.UnequalLengths =>
|
wenzelm@27326
|
101 |
error "Induction rule has different numbers of variables";
|
wenzelm@27326
|
102 |
in res_inst_tac ctxt insts rule' i st end
|
wenzelm@27326
|
103 |
handle THM _ => Seq.empty;
|
wenzelm@27326
|
104 |
|
wenzelm@27326
|
105 |
end;
|
wenzelm@27326
|
106 |
|
wenzelm@27326
|
107 |
fun induct_tac ctxt args = gen_induct_tac ctxt (args, NONE);
|
wenzelm@27326
|
108 |
fun induct_rules_tac ctxt args rules = gen_induct_tac ctxt (args, SOME rules);
|
wenzelm@27326
|
109 |
|
wenzelm@27326
|
110 |
|
wenzelm@27326
|
111 |
(* method syntax *)
|
wenzelm@27326
|
112 |
|
wenzelm@27326
|
113 |
local
|
wenzelm@27326
|
114 |
|
wenzelm@27326
|
115 |
val rule_spec = Scan.lift (Args.$$$ "rule" -- Args.$$$ ":");
|
wenzelm@27326
|
116 |
val opt_rule = Scan.option (rule_spec |-- Attrib.thm);
|
wenzelm@27326
|
117 |
val opt_rules = Scan.option (rule_spec |-- Attrib.thms);
|
wenzelm@27326
|
118 |
|
wenzelm@27326
|
119 |
val varss =
|
wenzelm@27809
|
120 |
OuterParse.and_list' (Scan.repeat (Scan.unless rule_spec (Scan.lift (Args.maybe Args.name))));
|
wenzelm@27326
|
121 |
|
wenzelm@27326
|
122 |
in
|
wenzelm@27326
|
123 |
|
wenzelm@27326
|
124 |
val setup =
|
wenzelm@27326
|
125 |
Method.add_methods
|
wenzelm@27326
|
126 |
[("case_tac", Method.goal_args_ctxt' (Scan.lift Args.name -- opt_rule) gen_case_tac,
|
wenzelm@27326
|
127 |
"unstructured case analysis on types"),
|
wenzelm@27326
|
128 |
("induct_tac", Method.goal_args_ctxt' (varss -- opt_rules) gen_induct_tac,
|
wenzelm@27326
|
129 |
"unstructured induction on types")];
|
wenzelm@27326
|
130 |
|
wenzelm@27326
|
131 |
end;
|
wenzelm@27326
|
132 |
|
wenzelm@27326
|
133 |
end;
|
wenzelm@27326
|
134 |
|