171 |
171 |
172 (** guess **) |
172 (** guess **) |
173 |
173 |
174 local |
174 local |
175 |
175 |
176 fun match_params ctxt vars rule = |
176 fun unify_params ctxt vars raw_rule = |
177 let |
177 let |
178 val thy = ProofContext.theory_of ctxt; |
178 val thy = ProofContext.theory_of ctxt; |
179 val string_of_typ = ProofContext.string_of_typ ctxt; |
179 val string_of_typ = ProofContext.string_of_typ ctxt; |
180 val string_of_term = setmp show_types true (ProofContext.string_of_term ctxt); |
180 val string_of_term = setmp show_types true (ProofContext.string_of_term ctxt); |
181 |
181 |
182 fun err msg th = error (msg ^ ":\n" ^ ProofContext.string_of_thm ctxt th); |
182 fun err msg th = error (msg ^ ":\n" ^ ProofContext.string_of_thm ctxt th); |
183 |
183 |
|
184 val maxidx = fold (Term.maxidx_typ o snd) vars ~1; |
|
185 val rule = Thm.incr_indexes (maxidx + 1) raw_rule; |
|
186 |
184 val params = RuleCases.strip_params (Logic.nth_prem (1, Thm.prop_of rule)); |
187 val params = RuleCases.strip_params (Logic.nth_prem (1, Thm.prop_of rule)); |
185 val m = length vars; |
188 val m = length vars; |
186 val n = length params; |
189 val n = length params; |
187 val _ = conditional (m > n) |
190 val _ = m <= n orelse err "More variables than parameters in obtained rule" rule; |
188 (fn () => err "More variables than parameters in obtained rule" rule); |
191 |
189 |
192 fun unify ((x, T), (y, U)) (tyenv, max) = Sign.typ_unify thy (T, U) (tyenv, max) |
190 fun match ((x, SOME T), (y, U)) tyenv = |
193 handle Type.TUNIFY => |
191 ((x, T), Sign.typ_match thy (U, T) tyenv handle Type.TYPE_MATCH => |
194 err ("Failed to unify variable " ^ |
192 err ("Failed to match variable " ^ |
195 string_of_term (Free (x, Envir.norm_type tyenv T)) ^ " against parameter " ^ |
193 string_of_term (Free (x, T)) ^ " against parameter " ^ |
196 string_of_term (Syntax.mark_boundT (y, Envir.norm_type tyenv U)) ^ " in") rule; |
194 string_of_term (Syntax.mark_boundT (y, Envir.norm_type tyenv U)) ^ " in") rule) |
197 val (tyenv, _) = fold unify (vars ~~ Library.take (m, params)) |
195 | match ((x, NONE), (_, U)) tyenv = ((x, U), tyenv); |
198 (Vartab.empty, Int.max (maxidx, Thm.maxidx_of rule)); |
196 val (xs, tyenv) = fold_map match (vars ~~ Library.take (m, params)) Vartab.empty; |
|
197 val ys = Library.drop (m, params); |
|
198 val norm_type = Envir.norm_type tyenv; |
199 val norm_type = Envir.norm_type tyenv; |
199 |
200 |
200 val xs' = xs |> map (apsnd norm_type); |
201 val xs = map (apsnd norm_type) vars; |
201 val ys' = |
202 val ys = map (apsnd norm_type) (Library.drop (m, params)); |
202 map Syntax.internal (Term.variantlist (map fst ys, map fst xs)) ~~ |
203 val ys' = map Syntax.internal (Term.variantlist (map fst ys, map fst xs)) ~~ map #2 ys; |
203 map (norm_type o snd) ys; |
204 |
204 val instT = |
205 val instT = |
205 fold (Term.add_tvarsT o #2) params [] |
206 fold (Term.add_tvarsT o #2) params [] |
206 |> map (TVar #> (fn T => (Thm.ctyp_of thy T, Thm.ctyp_of thy (norm_type T)))); |
207 |> map (TVar #> (fn T => (Thm.ctyp_of thy T, Thm.ctyp_of thy (norm_type T)))); |
207 val rule' = rule |> Thm.instantiate (instT, []); |
208 val rule' = rule |> Thm.instantiate (instT, []); |
208 |
209 |
210 val vars = subtract (op =) (Term.add_vars (Thm.concl_of rule') []) (Drule.vars_of rule'); |
211 val vars = subtract (op =) (Term.add_vars (Thm.concl_of rule') []) (Drule.vars_of rule'); |
211 val _ = |
212 val _ = |
212 if null tvars andalso null vars then () |
213 if null tvars andalso null vars then () |
213 else err ("Illegal schematic variable(s) " ^ |
214 else err ("Illegal schematic variable(s) " ^ |
214 commas (map (string_of_typ o TVar) tvars @ map (string_of_term o Var) vars) ^ " in") rule'; |
215 commas (map (string_of_typ o TVar) tvars @ map (string_of_term o Var) vars) ^ " in") rule'; |
215 in (xs' @ ys', rule') end; |
216 in (xs @ ys', rule') end; |
216 |
217 |
217 fun inferred_type (x, _, mx) ctxt = |
218 fun inferred_type (x, _, mx) ctxt = |
218 let val ((_, T), ctxt') = ProofContext.inferred_param x ctxt |
219 let val ((_, T), ctxt') = ProofContext.inferred_param x ctxt |
219 in ((x, SOME T, mx), ctxt') end; |
220 in ((x, T, mx), ctxt') end; |
|
221 |
|
222 fun polymorphic (vars, ctxt) = |
|
223 let val Ts = map Logic.dest_type (ProofContext.polymorphic ctxt (map (Logic.mk_type o #2) vars)) |
|
224 in map2 (fn (x, _, mx) => fn T => ((x, T), mx)) vars Ts end; |
220 |
225 |
221 fun gen_guess prep_vars raw_vars int state = |
226 fun gen_guess prep_vars raw_vars int state = |
222 let |
227 let |
223 val _ = Proof.assert_forward_or_chain state; |
228 val _ = Proof.assert_forward_or_chain state; |
224 val thy = Proof.theory_of state; |
229 val thy = Proof.theory_of state; |
225 val ctxt = Proof.context_of state; |
230 val ctxt = Proof.context_of state; |
226 val chain_facts = if can Proof.assert_chain state then Proof.the_facts state else []; |
231 val chain_facts = if can Proof.assert_chain state then Proof.the_facts state else []; |
227 |
232 |
228 val (thesis_var, thesis) = bind_judgment ctxt AutoBind.thesisN; |
233 val (thesis_var, thesis) = bind_judgment ctxt AutoBind.thesisN; |
229 val (vars, _) = ctxt |> prep_vars (map Syntax.no_syn raw_vars) |-> fold_map inferred_type; |
234 val vars = ctxt |> prep_vars (map Syntax.no_syn raw_vars) |
|
235 |-> fold_map inferred_type |> polymorphic; |
230 |
236 |
231 fun check_result th = |
237 fun check_result th = |
232 (case Thm.prems_of th of |
238 (case Thm.prems_of th of |
233 [prem] => |
239 [prem] => |
234 if Thm.concl_of th aconv thesis andalso |
240 if Thm.concl_of th aconv thesis andalso |
235 Logic.strip_assums_concl prem aconv thesis then () |
241 Logic.strip_assums_concl prem aconv thesis then () |
236 else error ("Guessed a different clause:\n" ^ ProofContext.string_of_thm ctxt th) |
242 else error ("Guessed a different clause:\n" ^ ProofContext.string_of_thm ctxt th) |
237 | [] => error "Goal solved -- nothing guessed." |
243 | [] => error "Goal solved -- nothing guessed." |
238 | _ => error ("Guess split into several cases:\n" ^ ProofContext.string_of_thm ctxt th)); |
244 | _ => error ("Guess split into several cases:\n" ^ ProofContext.string_of_thm ctxt th)); |
239 |
245 |
240 fun guess_context raw_rule = |
246 fun guess_context [_, raw_rule] = |
241 let |
247 let |
242 val (parms, rule) = match_params ctxt (map (fn (x, T, _) => (x, T)) vars) raw_rule; |
248 val (parms, rule) = unify_params ctxt (map #1 vars) raw_rule; |
243 val (bind, _) = ProofContext.bind_fixes (map #1 parms) ctxt; |
249 val (bind, _) = ProofContext.bind_fixes (map #1 parms) ctxt; |
244 val ts = map (bind o Free) parms; |
250 val ts = map (bind o Free) parms; |
245 val ps = map dest_Free ts; |
251 val ps = map dest_Free ts; |
246 val asms = |
252 val asms = |
247 Logic.strip_assums_hyp (Logic.nth_prem (1, Thm.prop_of rule)) |
253 Logic.strip_assums_hyp (Logic.nth_prem (1, Thm.prop_of rule)) |
248 |> map (fn asm => (Term.betapplys (Term.list_abs (ps, asm), ts), [])); |
254 |> map (fn asm => (Term.betapplys (Term.list_abs (ps, asm), ts), [])); |
249 val _ = conditional (null asms) (fn () => error "Trivial result -- nothing guessed"); |
255 val _ = not (null asms) orelse error "Trivial result -- nothing guessed"; |
250 in |
256 in |
251 Proof.fix_i (map (apsnd SOME) parms) |
257 Proof.fix_i (map (apsnd SOME) parms) |
252 #> Proof.assm_i (K (obtain_export ctxt ts rule)) [(("", []), asms)] |
258 #> Proof.assm_i (K (obtain_export ctxt ts rule)) [(("", []), asms)] |
253 #> Proof.add_binds_i AutoBind.no_facts |
259 #> Proof.add_binds_i AutoBind.no_facts |
254 end; |
260 end; |
255 |
261 |
256 val before_qed = SOME (Method.primitive_text (Goal.conclude #> Goal.protect)); |
262 val goal = Var (("guess", 0), propT); |
257 fun after_qed [[res]] = |
263 fun print_result ctxt' (k, [(s, [_, th])]) = |
258 (check_result res; Proof.end_block #> Seq.map (`Proof.the_fact #-> guess_context)); |
264 ProofDisplay.print_results int ctxt' (k, [(s, [th])]); |
|
265 val before_qed = SOME (Method.primitive_text (Goal.conclude #> (fn th => |
|
266 Goal.protect (Conjunction.intr (Drule.mk_term (Thm.cprop_of th)) th)))); |
|
267 fun after_qed [[_, res]] = |
|
268 (check_result res; Proof.end_block #> Seq.map (`Proof.the_facts #-> guess_context)); |
259 in |
269 in |
260 state |
270 state |
261 |> Proof.enter_forward |
271 |> Proof.enter_forward |
262 |> Proof.begin_block |
272 |> Proof.begin_block |
263 |> Proof.fix_i [(AutoBind.thesisN, NONE)] |
273 |> Proof.fix_i [(AutoBind.thesisN, NONE)] |
264 |> Proof.chain_facts chain_facts |
274 |> Proof.chain_facts chain_facts |
265 |> Proof.local_goal (ProofDisplay.print_results int) (K I) (apsnd (rpair I)) |
275 |> Proof.local_goal print_result (K I) (apsnd (rpair I)) |
266 "guess" before_qed after_qed [(("", []), [Var (("guess", 0), propT)])] |
276 "guess" before_qed after_qed [(("", []), [Logic.mk_term goal, goal])] |
267 |> Proof.refine (Method.primitive_text (K (Goal.init (Thm.cterm_of thy thesis)))) |> Seq.hd |
277 |> Proof.refine (Method.primitive_text (K (Goal.init (Thm.cterm_of thy thesis)))) |> Seq.hd |
268 end; |
278 end; |
269 |
279 |
270 in |
280 in |
271 |
281 |