src/Pure/Isar/obtain.ML
changeset 19779 5c77dfb74c7b
parent 19585 70a1ce3b23ae
child 19844 2c1fdc397ded
equal deleted inserted replaced
19778:f0a318495ca4 19779:5c77dfb74c7b
   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