18 end |
18 end |
19 |
19 |
20 signature RULE_CASES = |
20 signature RULE_CASES = |
21 sig |
21 sig |
22 include BASIC_RULE_CASES |
22 include BASIC_RULE_CASES |
23 type T |
23 datatype T = Case of |
|
24 {fixes: (string * typ) list, |
|
25 assumes: (string * term list) list, |
|
26 binds: (indexname * term option) list, |
|
27 cases: (string * T) list} |
|
28 val strip_params: term -> (string * typ) list |
|
29 val make_common: bool -> theory * term -> (string * string list) list -> cases |
|
30 val make_nested: bool -> term -> theory * term -> (string * string list) list -> cases |
|
31 val make_simple: bool -> theory * term -> string -> cases |
|
32 val apply: term list -> T -> T |
24 val consume: thm list -> thm list -> ('a * int) * thm -> |
33 val consume: thm list -> thm list -> ('a * int) * thm -> |
25 (('a * (int * thm list)) * thm) Seq.seq |
34 (('a * (int * thm list)) * thm) Seq.seq |
26 val add_consumes: int -> thm -> thm |
35 val add_consumes: int -> thm -> thm |
27 val consumes: int -> 'a attribute |
36 val consumes: int -> 'a attribute |
28 val consumes_default: int -> 'a attribute |
37 val consumes_default: int -> 'a attribute |
29 val name: string list -> thm -> thm |
38 val name: string list -> thm -> thm |
30 val case_names: string list -> 'a attribute |
39 val case_names: string list -> 'a attribute |
31 val case_conclusion: string * string list -> 'a attribute |
40 val case_conclusion: string * string list -> 'a attribute |
32 val save: thm -> thm -> thm |
41 val save: thm -> thm -> thm |
33 val get: thm -> (string * string list) list * int |
42 val get: thm -> (string * string list) list * int |
34 val strip_params: term -> (string * typ) list |
|
35 val make: bool -> term option -> theory * term -> (string * string list) list -> cases |
|
36 val simple: theory * term -> string -> cases |
|
37 val rename_params: string list list -> thm -> thm |
43 val rename_params: string list list -> thm -> thm |
38 val params: string list list -> 'a attribute |
44 val params: string list list -> 'a attribute |
39 val mutual_rule: thm list -> (int list * thm) option |
45 val mutual_rule: thm list -> (int list * thm) option |
40 val strict_mutual_rule: thm list -> int list * thm |
46 val strict_mutual_rule: thm list -> int list * thm |
41 end; |
47 end; |
42 |
48 |
43 structure RuleCases: RULE_CASES = |
49 structure RuleCases: RULE_CASES = |
44 struct |
50 struct |
45 |
51 |
46 (** tactics with cases **) |
52 (** cases **) |
47 |
53 |
48 type T = |
54 datatype T = Case of |
49 {fixes: (string * typ) list, |
55 {fixes: (string * typ) list, |
50 assumes: (string * term list) list, |
56 assumes: (string * term list) list, |
51 binds: (indexname * term option) list}; |
57 binds: (indexname * term option) list, |
|
58 cases: (string * T) list}; |
52 |
59 |
53 type cases = (string * T option) list; |
60 type cases = (string * T option) list; |
|
61 |
|
62 val case_conclN = "case"; |
|
63 val case_hypsN = "hyps"; |
|
64 val case_premsN = "prems"; |
|
65 |
|
66 val strip_params = map (apfst (perhaps (try Syntax.dest_skolem))) o Logic.strip_params; |
|
67 |
|
68 local |
|
69 |
|
70 fun abs xs t = Term.list_abs (xs, t); |
|
71 fun app us t = Term.betapplys (t, us); |
|
72 |
|
73 fun dest_binops cs tm = |
|
74 let |
|
75 val n = length cs; |
|
76 fun dest 0 _ = [] |
|
77 | dest 1 t = [t] |
|
78 | dest k (_ $ t $ u) = t :: dest (k - 1) u |
|
79 | dest _ _ = raise TERM ("Expected " ^ string_of_int n ^ " binop arguments", [tm]); |
|
80 in cs ~~ dest n tm end; |
|
81 |
|
82 fun extract_fixes NONE prop = (strip_params prop, []) |
|
83 | extract_fixes (SOME outline) prop = |
|
84 splitAt (length (Logic.strip_params outline), strip_params prop); |
|
85 |
|
86 fun extract_assumes _ NONE prop = ([("", Logic.strip_assums_hyp prop)], []) |
|
87 | extract_assumes qual (SOME outline) prop = |
|
88 let val (hyps, prems) = |
|
89 splitAt (length (Logic.strip_assums_hyp outline), Logic.strip_assums_hyp prop) |
|
90 in ([(qual case_hypsN, hyps)], [(qual case_premsN, prems)]) end; |
|
91 |
|
92 fun extract_case is_open thy (case_outline, raw_prop) name concls = |
|
93 let |
|
94 val rename = if is_open then I else (apfst Syntax.internal); |
|
95 |
|
96 val props = Logic.dest_conjunctions (Drule.norm_hhf thy raw_prop); |
|
97 val len = length props; |
|
98 val nested = is_some case_outline andalso len > 1; |
|
99 |
|
100 fun extract prop = |
|
101 let |
|
102 val (fixes1, fixes2) = extract_fixes case_outline prop |
|
103 |> apfst (map rename); |
|
104 val abs_fixes = abs (fixes1 @ fixes2); |
|
105 fun abs_fixes1 t = |
|
106 if not nested then abs_fixes t |
|
107 else abs fixes1 (app (map (Term.dummy_pattern o #2) fixes2) (abs fixes2 t)); |
|
108 |
|
109 val (assumes1, assumes2) = extract_assumes (NameSpace.qualified name) case_outline prop |
|
110 |> pairself (map (apsnd (List.concat o map Logic.dest_conjunctions))); |
|
111 |
|
112 val concl = ObjectLogic.drop_judgment thy (Logic.strip_assums_concl prop); |
|
113 val binds = |
|
114 (case_conclN, concl) :: dest_binops concls concl |
|
115 |> map (fn (x, t) => ((x, 0), SOME (abs_fixes t))); |
|
116 in |
|
117 ((fixes1, map (apsnd (map abs_fixes1)) assumes1), |
|
118 ((fixes2, map (apsnd (map abs_fixes)) assumes2), binds)) |
|
119 end; |
|
120 |
|
121 val cases = map extract props; |
|
122 |
|
123 fun common_case ((fixes1, assumes1), ((fixes2, assumes2), binds)) = |
|
124 Case {fixes = fixes1 @ fixes2, assumes = assumes1 @ assumes2, binds = binds, cases = []}; |
|
125 fun inner_case (_, ((fixes2, assumes2), binds)) = |
|
126 Case {fixes = fixes2, assumes = assumes2, binds = binds, cases = []}; |
|
127 fun nested_case ((fixes1, assumes1), _) = |
|
128 Case {fixes = fixes1, assumes = assumes1, binds = [], |
|
129 cases = map string_of_int (1 upto len) ~~ map inner_case cases}; |
|
130 in |
|
131 if len = 0 then NONE |
|
132 else if len = 1 then SOME (common_case (hd cases)) |
|
133 else if is_none case_outline orelse length (gen_distinct (op =) (map fst cases)) > 1 then NONE |
|
134 else SOME (nested_case (hd cases)) |
|
135 end; |
|
136 |
|
137 fun make is_open rule_struct (thy, prop) cases = |
|
138 let |
|
139 val n = length cases; |
|
140 val nprems = Logic.count_prems (prop, 0); |
|
141 fun add_case (name, concls) (cs, i) = |
|
142 ((case try (fn () => |
|
143 (Option.map (curry Logic.nth_prem i) rule_struct, Logic.nth_prem (i, prop))) () of |
|
144 NONE => (name, NONE) |
|
145 | SOME p => (name, extract_case is_open thy p name concls)) :: cs, i - 1); |
|
146 in fold_rev add_case (Library.drop (n - nprems, cases)) ([], n) |> #1 end; |
|
147 |
|
148 in |
|
149 |
|
150 fun make_common is_open = make is_open NONE; |
|
151 fun make_nested is_open rule_struct = make is_open (SOME rule_struct); |
|
152 fun make_simple is_open (thy, prop) name = [(name, extract_case is_open thy (NONE, prop) "" [])]; |
|
153 |
|
154 fun apply args = |
|
155 let |
|
156 fun appl (Case {fixes, assumes, binds, cases}) = |
|
157 let |
|
158 val assumes' = map (apsnd (map (app args))) assumes; |
|
159 val binds' = map (apsnd (Option.map (app args))) binds; |
|
160 val cases' = map (apsnd appl) cases; |
|
161 in Case {fixes = fixes, assumes = assumes', binds = binds', cases = cases'} end; |
|
162 in appl end; |
|
163 |
|
164 end; |
|
165 |
|
166 |
|
167 |
|
168 (** tactics with cases **) |
|
169 |
54 type cases_tactic = thm -> (cases * thm) Seq.seq; |
170 type cases_tactic = thm -> (cases * thm) Seq.seq; |
55 |
171 |
56 fun CASES cases tac st = Seq.map (pair cases) (tac st); |
172 fun CASES cases tac st = Seq.map (pair cases) (tac st); |
57 fun NO_CASES tac = CASES [] tac; |
173 fun NO_CASES tac = CASES [] tac; |
58 |
174 |
177 val cases = |
293 val cases = |
178 (case lookup_case_names th of |
294 (case lookup_case_names th of |
179 NONE => map (rpair [] o Library.string_of_int) (1 upto (Thm.nprems_of th - n)) |
295 NONE => map (rpair [] o Library.string_of_int) (1 upto (Thm.nprems_of th - n)) |
180 | SOME names => map (fn name => (name, get_case_concls th name)) names); |
296 | SOME names => map (fn name => (name, get_case_concls th name)) names); |
181 in (cases, n) end; |
297 in (cases, n) end; |
182 |
|
183 |
|
184 (* extract cases *) |
|
185 |
|
186 val case_conclN = "case"; |
|
187 val case_hypsN = "hyps"; |
|
188 val case_premsN = "prems"; |
|
189 |
|
190 val strip_params = map (apfst (perhaps (try Syntax.dest_skolem))) o Logic.strip_params; |
|
191 |
|
192 local |
|
193 |
|
194 fun dest_binops cs tm = |
|
195 let |
|
196 val n = length cs; |
|
197 fun dest 0 _ = [] |
|
198 | dest 1 t = [t] |
|
199 | dest k (_ $ t $ u) = t :: dest (k - 1) u |
|
200 | dest _ _ = raise TERM ("Expected " ^ string_of_int n ^ " binop arguments", [tm]); |
|
201 in cs ~~ dest n tm end; |
|
202 |
|
203 fun extract_cases is_open thy (split, raw_prop) name concls = |
|
204 let |
|
205 fun extract prop idx = |
|
206 let |
|
207 val xs = strip_params prop; |
|
208 val rename = if is_open then I else map (apfst Syntax.internal); |
|
209 val fixes = |
|
210 (case split of |
|
211 NONE => rename xs |
|
212 | SOME t => |
|
213 let val (us, vs) = splitAt (length (Logic.strip_params t), xs) |
|
214 in rename us @ vs end); |
|
215 fun abs_fixes t = Term.list_abs (fixes, t); |
|
216 val dest_conjuncts = map abs_fixes o List.concat o map Logic.dest_conjunctions; |
|
217 |
|
218 val asms = Logic.strip_assums_hyp prop; |
|
219 val assumes = |
|
220 (case split of |
|
221 NONE => [("", dest_conjuncts asms)] |
|
222 | SOME t => |
|
223 let val (hyps, prems) = splitAt (length (Logic.strip_assums_hyp t), asms) in |
|
224 [(case_hypsN, dest_conjuncts hyps), |
|
225 (case_premsN, dest_conjuncts prems)] |
|
226 end); |
|
227 |
|
228 val concl = ObjectLogic.drop_judgment thy (Logic.strip_assums_concl prop); |
|
229 val binds = (case_conclN, concl) :: dest_binops concls concl |
|
230 |> map (fn (x, t) => ((x, 0), SOME (abs_fixes t))); |
|
231 in (name ^ idx, SOME {fixes = fixes, assumes = assumes, binds = binds}) end; |
|
232 in |
|
233 (case Logic.dest_conjunctions (Drule.norm_hhf thy raw_prop) of |
|
234 [prop] => [extract prop ""] |
|
235 | props => map2 extract props (map string_of_int (1 upto length props))) |
|
236 end; |
|
237 |
|
238 in |
|
239 |
|
240 fun make is_open split (thy, prop) cases = |
|
241 let |
|
242 val n = length cases; |
|
243 val nprems = Logic.count_prems (prop, 0); |
|
244 fun add_case (name, concls) (cs, i) = |
|
245 ((case try (fn () => |
|
246 (Option.map (curry Logic.nth_prem i) split, Logic.nth_prem (i, prop))) () of |
|
247 NONE => [(name, NONE)] |
|
248 | SOME sp => extract_cases is_open thy sp name concls) @ cs, i - 1); |
|
249 in fold_rev add_case (Library.drop (n - nprems, cases)) ([], n) |> #1 end; |
|
250 |
|
251 fun simple (thy, prop) name = |
|
252 extract_cases true thy (NONE, prop) name []; |
|
253 |
|
254 end; |
|
255 |
298 |
256 |
299 |
257 (* params *) |
300 (* params *) |
258 |
301 |
259 fun rename_params xss th = |
302 fun rename_params xss th = |