18120

1 
(* Title: Pure/old_goals.ML


2 
ID: $Id$


3 
Author: Lawrence C Paulson, Cambridge University Computer Laboratory


4 
Copyright 1993 University of Cambridge


5 


6 
Oldstyle goal stack package. The goal stack initially holds a dummy


7 
proof, and can never become empty. Each goal stack consists of a list


8 
of levels. The undo list is a list of goal stacks. Finally, there


9 
may be a stack of pending proofs.


10 
*)


11 


12 
signature GOALS =


13 
sig


14 
val premises: unit > thm list


15 
val prove_goal: theory > string > (thm list > tactic list) > thm


16 
val prove_goalw: theory > thm list > string > (thm list > tactic list) > thm


17 
val disable_pr: unit > unit


18 
val enable_pr: unit > unit


19 
val topthm: unit > thm


20 
val result: unit > thm


21 
val uresult: unit > thm


22 
val getgoal: int > term


23 
val gethyps: int > thm list


24 
val prlev: int > unit


25 
val pr: unit > unit


26 
val prlim: int > unit


27 
val goal: theory > string > thm list


28 
val goalw: theory > thm list > string > thm list


29 
val Goal: string > thm list


30 
val Goalw: thm list > string > thm list


31 
val by: tactic > unit


32 
val back: unit > unit


33 
val choplev: int > unit


34 
val chop: unit > unit


35 
val undo: unit > unit


36 
val bind_thm: string * thm > unit


37 
val bind_thms: string * thm list > unit


38 
val qed: string > unit


39 
val qed_goal: string > theory > string > (thm list > tactic list) > unit


40 
val qed_goalw: string > theory > thm list > string


41 
> (thm list > tactic list) > unit


42 
val qed_spec_mp: string > unit


43 
val qed_goal_spec_mp: string > theory > string > (thm list > tactic list) > unit


44 
val qed_goalw_spec_mp: string > theory > thm list > string


45 
> (thm list > tactic list) > unit


46 
val no_qed: unit > unit


47 
val thms_containing: xstring list > (string * thm) list


48 
end;


49 


50 
signature OLD_GOALS =


51 
sig


52 
include GOALS


53 
val legacy: bool ref


54 
type proof


55 
val reset_goals: unit > unit


56 
val result_error_fn: (thm > string > thm) ref


57 
val print_sign_exn: theory > exn > 'a


58 
val prove_goalw_cterm: thm list>cterm>(thm list>tactic list)>thm


59 
val prove_goalw_cterm_nocheck: thm list>cterm>(thm list>tactic list)>thm


60 
val quick_and_dirty_prove_goalw_cterm: theory > thm list > cterm


61 
> (thm list > tactic list) > thm


62 
val print_exn: exn > 'a


63 
val filter_goal: (term*term>bool) > thm list > int > thm list


64 
val goalw_cterm: thm list > cterm > thm list


65 
val simple_prove_goal_cterm: cterm>(thm list>tactic list)>thm


66 
val byev: tactic list > unit


67 
val save_proof: unit > proof


68 
val restore_proof: proof > thm list


69 
val push_proof: unit > unit


70 
val pop_proof: unit > thm list


71 
val rotate_proof: unit > thm list


72 
val bws: thm list > unit


73 
val bw: thm > unit


74 
val brs: thm list > int > unit


75 
val br: thm > int > unit


76 
val bes: thm list > int > unit


77 
val be: thm > int > unit


78 
val bds: thm list > int > unit


79 
val bd: thm > int > unit


80 
val ba: int > unit


81 
val ren: string > int > unit


82 
val frs: thm list > unit


83 
val fr: thm > unit


84 
val fes: thm list > unit


85 
val fe: thm > unit


86 
val fds: thm list > unit


87 
val fd: thm > unit


88 
val fa: unit > unit


89 
end;


90 


91 
structure OldGoals: OLD_GOALS =


92 
struct


93 


94 
val legacy = ref false;


95 
fun warn_obsolete () = if ! legacy then () else warning "Obsolete goal command encountered";


96 


97 


98 
(*** Goal package ***)


99 


100 
(*Each level of goal stack includes a proof state and alternative states,


101 
the output of the tactic applied to the preceeding level. *)


102 
type gstack = (thm * thm Seq.seq) list;


103 


104 
datatype proof = Proof of gstack list * thm list * (bool*thm>thm);


105 


106 


107 
(*** References ***)


108 


109 
(*Current assumption list  set by "goal".*)


110 
val curr_prems = ref([] : thm list);


111 


112 
(*Return assumption list  useful if you didn't save "goal"'s result. *)


113 
fun premises() = !curr_prems;


114 


115 
(*Current result maker  set by "goal", used by "result". *)


116 
fun init_mkresult _ = error "No goal has been supplied in subgoal module";


117 
val curr_mkresult = ref (init_mkresult: bool*thm>thm);


118 


119 
val dummy = Thm.trivial (read_cterm ProtoPure.thy ("PROP No_goal_has_been_supplied", propT));


120 


121 
(*List of previous goal stacks, for the undo operation. Set by setstate.


122 
A list of lists!*)


123 
val undo_list = ref([[(dummy, Seq.empty)]] : gstack list);


124 


125 
(* Stack of proof attempts *)


126 
val proofstack = ref([]: proof list);


127 


128 
(*reset all refs*)


129 
fun reset_goals () =


130 
(curr_prems := []; curr_mkresult := init_mkresult;


131 
undo_list := [[(dummy, Seq.empty)]]);


132 


133 


134 
(*** Setting up goaldirected proof ***)


135 


136 
(*Generates the list of new theories when the proof state's theory changes*)


137 
fun thy_error (thy,thy') =


138 
let val names = Context.names_of thy' \\ Context.names_of thy


139 
in case names of


140 
[name] => "\nNew theory: " ^ name


141 
 _ => "\nNew theories: " ^ space_implode ", " names


142 
end;


143 


144 
(*Default action is to print an error message; could be suppressed for


145 
special applications.*)


146 
fun result_error_default state msg : thm =


147 
Pretty.str "Bad final proof state:" :: Display.pretty_goals (!goals_limit) state @


148 
[Pretty.str msg, Pretty.str "Proof failed!"] > Pretty.chunks > Pretty.string_of > error;


149 


150 
val result_error_fn = ref result_error_default;


151 


152 


153 
(*Common treatment of "goal" and "prove_goal":


154 
Return assumptions, initial proof state, and function to make result.


155 
"atomic" indicates if the goal should be wrapped up in the function


156 
"Goal::prop=>prop" to avoid assumptions being returned separately.


157 
*)


158 
fun prepare_proof atomic rths chorn =


159 
let


160 
val _ = warn_obsolete ();


161 
val {thy, t=horn,...} = rep_cterm chorn;


162 
val _ = Term.no_dummy_patterns horn handle TERM (msg, _) => error msg;


163 
val (As, B) = Logic.strip_horn horn;


164 
val atoms = atomic andalso


165 
forall (fn t => not(Logic.is_implies t orelse Logic.is_all t)) As;


166 
val (As,B) = if atoms then ([],horn) else (As,B);


167 
val cAs = map (cterm_of thy) As;


168 
val prems = map (rewrite_rule rths o forall_elim_vars 0 o Thm.assume) cAs;


169 
val cB = cterm_of thy B;


170 
val st0 = let val st = Goal.init cB > fold Thm.weaken cAs


171 
in rewrite_goals_rule rths st end


172 
(*discharges assumptions from state in the order they appear in goal;


173 
checks (if requested) that resulting theorem is equivalent to goal. *)


174 
fun mkresult (check,state) =


175 
let val state = Seq.hd (flexflex_rule state)


176 
handle THM _ => state (*smash flexflex pairs*)


177 
val ngoals = nprems_of state


178 
val ath = implies_intr_list cAs state


179 
val th = Goal.conclude ath


180 
val {hyps,prop,thy=thy',...} = rep_thm th


181 
val final_th = standard th


182 
in if not check then final_th


183 
else if not (eq_thy(thy,thy')) then !result_error_fn state


184 
("Theory of proof state has changed!" ^


185 
thy_error (thy,thy'))


186 
else if ngoals>0 then !result_error_fn state


187 
(string_of_int ngoals ^ " unsolved goals!")


188 
else if not (null hyps) then !result_error_fn state


189 
("Additional hypotheses:\n" ^


190 
cat_lines (map (Sign.string_of_term thy) hyps))


191 
else if Pattern.matches thy


192 
(Envir.beta_norm (term_of chorn), Envir.beta_norm prop)


193 
then final_th


194 
else !result_error_fn state "proved a different theorem"


195 
end


196 
in


197 
if eq_thy(thy, Thm.theory_of_thm st0)


198 
then (prems, st0, mkresult)


199 
else error ("Definitions would change the proof state's theory" ^


200 
thy_error (thy, Thm.theory_of_thm st0))


201 
end


202 
handle THM(s,_,_) => error("prepare_proof: exception THM was raised!\n" ^ s);


203 


204 
(*Prints exceptions readably to users*)


205 
fun print_sign_exn_unit thy e =


206 
case e of


207 
THM (msg,i,thms) =>


208 
(writeln ("Exception THM " ^ string_of_int i ^ " raised:\n" ^ msg);


209 
List.app print_thm thms)


210 
 THEORY (msg,thys) =>


211 
(writeln ("Exception THEORY raised:\n" ^ msg);


212 
List.app (writeln o Context.str_of_thy) thys)


213 
 TERM (msg,ts) =>


214 
(writeln ("Exception TERM raised:\n" ^ msg);


215 
List.app (writeln o Sign.string_of_term thy) ts)


216 
 TYPE (msg,Ts,ts) =>


217 
(writeln ("Exception TYPE raised:\n" ^ msg);


218 
List.app (writeln o Sign.string_of_typ thy) Ts;


219 
List.app (writeln o Sign.string_of_term thy) ts)


220 
 e => raise e;


221 


222 
(*Prints an exception, then fails*)

18678

223 
fun print_sign_exn thy e = (print_sign_exn_unit thy e; raise ERROR "");

18120

224 


225 
(** the prove_goal.... commands


226 
Prove theorem using the listed tactics; check it has the specified form.


227 
Augment theory with all type assignments of goal.


228 
Syntax is similar to "goal" command for easy keyboard use. **)


229 


230 
(*Version taking the goal as a cterm*)


231 
fun prove_goalw_cterm_general check rths chorn tacsf =


232 
let val (prems, st0, mkresult) = prepare_proof false rths chorn


233 
val tac = EVERY (tacsf prems)


234 
fun statef() =


235 
(case Seq.pull (tac st0) of


236 
SOME(st,_) => st


237 
 _ => error ("prove_goal: tactic failed"))


238 
in mkresult (check, cond_timeit (!Output.timing) statef) end


239 
handle e => (print_sign_exn_unit (#thy (rep_cterm chorn)) e;


240 
writeln ("The exception above was raised for\n" ^


241 
Display.string_of_cterm chorn); raise e);


242 


243 
(*Two variants: one checking the result, one not.


244 
Neither prints runtime messages: they are for internal packages.*)


245 
fun prove_goalw_cterm rths chorn =


246 
setmp Output.timing false (prove_goalw_cterm_general true rths chorn)


247 
and prove_goalw_cterm_nocheck rths chorn =


248 
setmp Output.timing false (prove_goalw_cterm_general false rths chorn);


249 


250 


251 
(*Version taking the goal as a string*)


252 
fun prove_goalw thy rths agoal tacsf =


253 
let val chorn = read_cterm thy (agoal, propT)


254 
in prove_goalw_cterm_general true rths chorn tacsf end

18678

255 
handle ERROR msg => cat_error msg (*from read_cterm?*)

18120

256 
("The error(s) above occurred for " ^ quote agoal);


257 


258 
(*String version with no metarewriterules*)


259 
fun prove_goal thy = prove_goalw thy [];


260 


261 
(*quick and dirty version (conditional)*)


262 
fun quick_and_dirty_prove_goalw_cterm thy rews ct tacs =


263 
prove_goalw_cterm rews ct


264 
(if ! quick_and_dirty then (K [SkipProof.cheat_tac thy]) else tacs);


265 


266 


267 
(*** Commands etc ***)


268 


269 
(*Return the current goal stack, if any, from undo_list*)


270 
fun getstate() : gstack = case !undo_list of


271 
[] => error"No current state in subgoal module"


272 
 x::_ => x;


273 


274 
(*Pops the given goal stack*)


275 
fun pop [] = error"Cannot go back past the beginning of the proof!"


276 
 pop (pair::pairs) = (pair,pairs);


277 


278 


279 
(* Print a level of the goal stack  subject to quiet mode *)


280 


281 
val quiet = ref false;


282 
fun disable_pr () = quiet := true;


283 
fun enable_pr () = quiet := false;


284 


285 
fun print_top ((th, _), pairs) =


286 
if ! quiet then ()


287 
else ! Display.print_current_goals_fn (length pairs) (! goals_limit) th;


288 


289 
(*Printing can raise exceptions, so the assignment occurs last.


290 
Can do setstate[(st,Seq.empty)] to set st as the state. *)


291 
fun setstate newgoals =


292 
(print_top (pop newgoals); undo_list := newgoals :: !undo_list);


293 


294 
(*Given a proof state transformation, return a command that updates


295 
the goal stack*)


296 
fun make_command com = setstate (com (pop (getstate())));


297 


298 
(*Apply a function on proof states to the current goal stack*)


299 
fun apply_fun f = f (pop(getstate()));


300 


301 
(*Return the top theorem, representing the proof state*)


302 
fun topthm () = apply_fun (fn ((th,_), _) => th);


303 


304 
(*Return the final result. *)


305 
fun result () = !curr_mkresult (true, topthm());


306 


307 
(*Return the result UNCHECKED that it equals the goal  for synthesis,


308 
answer extraction, or other instantiation of Vars *)


309 
fun uresult () = !curr_mkresult (false, topthm());


310 


311 
(*Get subgoal i from goal stack*)


312 
fun getgoal i = Logic.get_goal (prop_of (topthm())) i;


313 


314 
(*Return subgoal i's hypotheses as metalevel assumptions.


315 
For debugging uses of METAHYPS*)


316 
local exception GETHYPS of thm list


317 
in


318 
fun gethyps i =


319 
(METAHYPS (fn hyps => raise (GETHYPS hyps)) i (topthm()); [])


320 
handle GETHYPS hyps => hyps


321 
end;


322 


323 
(*Prints exceptions nicely at top level;


324 
raises the exception in order to have a polymorphic type!*)


325 
fun print_exn e = (print_sign_exn_unit (Thm.theory_of_thm (topthm())) e; raise e);


326 


327 
(*Which thms could apply to goal i? (debugs tactics involving filter_thms) *)


328 
fun filter_goal could ths i = filter_thms could (999, getgoal i, ths);


329 


330 
(*For inspecting earlier levels of the backward proof*)


331 
fun chop_level n (pair,pairs) =


332 
let val level = length pairs


333 
in if n<0 andalso ~n <= level


334 
then List.drop (pair::pairs, ~n)


335 
else if 0<=n andalso n<= level


336 
then List.drop (pair::pairs, level  n)


337 
else error ("Level number must lie between 0 and " ^


338 
string_of_int level)


339 
end;


340 


341 
(*Print the given level of the proof; prlev ~1 prints previous level*)


342 
fun prlev n = (enable_pr (); apply_fun (print_top o pop o (chop_level n)));


343 
fun pr () = (enable_pr (); apply_fun print_top);


344 


345 
(*Set goals_limit and print again*)


346 
fun prlim n = (goals_limit:=n; pr());


347 


348 
(** the goal.... commands


349 
Read main goal. Set global variables curr_prems, curr_mkresult.


350 
Initial subgoal and premises are rewritten using rths. **)


351 


352 
(*Version taking the goal as a cterm; if you have a term t and theory thy, use


353 
goalw_cterm rths (cterm_of thy t); *)


354 
fun agoalw_cterm atomic rths chorn =


355 
let val (prems, st0, mkresult) = prepare_proof atomic rths chorn


356 
in undo_list := [];


357 
setstate [ (st0, Seq.empty) ];


358 
curr_prems := prems;


359 
curr_mkresult := mkresult;


360 
prems


361 
end;


362 


363 
val goalw_cterm = agoalw_cterm false;


364 


365 
(*Version taking the goal as a string*)


366 
fun agoalw atomic thy rths agoal =


367 
agoalw_cterm atomic rths (read_cterm thy (agoal, propT))

18678

368 
handle ERROR msg => cat_error msg (*from type_assign, etc via prepare_proof*)

18120

369 
("The error(s) above occurred for " ^ quote agoal);


370 


371 
val goalw = agoalw false;


372 
fun goal thy = goalw thy [];


373 


374 
(*now the versions that wrap the goal up in `Goal' to make it atomic*)


375 
fun Goalw thms s = agoalw true (Context.the_context ()) thms s;


376 
val Goal = Goalw [];


377 


378 
(*simple version with minimal amount of checking and postprocessing*)


379 
fun simple_prove_goal_cterm G f =


380 
let


381 
val _ = warn_obsolete ();


382 
val As = Drule.strip_imp_prems G;


383 
val B = Drule.strip_imp_concl G;


384 
val asms = map (Goal.norm_hhf o Thm.assume) As;


385 
fun check NONE = error "prove_goal: tactic failed"


386 
 check (SOME (thm, _)) = (case nprems_of thm of


387 
0 => thm


388 
 i => !result_error_fn thm (string_of_int i ^ " unsolved goals!"))


389 
in


390 
standard (implies_intr_list As


391 
(check (Seq.pull (EVERY (f asms) (trivial B)))))


392 
end;


393 


394 


395 
(*Proof step "by" the given tactic  apply tactic to the proof state*)


396 
fun by_com tac ((th,ths), pairs) : gstack =


397 
(case Seq.pull(tac th) of


398 
NONE => error"by: tactic failed"


399 
 SOME(th2,ths2) =>


400 
(if eq_thm(th,th2)


401 
then warning "Warning: same as previous level"


402 
else if eq_thm_thy(th,th2) then ()


403 
else warning ("Warning: theory of proof state has changed" ^


404 
thy_error (Thm.theory_of_thm th, Thm.theory_of_thm th2));


405 
((th2,ths2)::(th,ths)::pairs)));


406 


407 
fun by tac = cond_timeit (!Output.timing)


408 
(fn() => make_command (by_com tac));


409 


410 
(* byev[tac1,...,tacn] applies tac1 THEN ... THEN tacn.


411 
Good for debugging proofs involving prove_goal.*)


412 
val byev = by o EVERY;


413 


414 


415 
(*Backtracking means find an alternative result from a tactic.


416 
If none at this level, try earlier levels*)


417 
fun backtrack [] = error"back: no alternatives"


418 
 backtrack ((th,thstr) :: pairs) =


419 
(case Seq.pull thstr of


420 
NONE => (writeln"Going back a level..."; backtrack pairs)


421 
 SOME(th2,thstr2) =>


422 
(if eq_thm(th,th2)


423 
then warning "Warning: same as previous choice at this level"


424 
else if eq_thm_thy(th,th2) then ()


425 
else warning "Warning: theory of proof state has changed";


426 
(th2,thstr2)::pairs));


427 


428 
fun back() = setstate (backtrack (getstate()));


429 


430 
(*Chop back to previous level of the proof*)


431 
fun choplev n = make_command (chop_level n);


432 


433 
(*Chopping back the goal stack*)


434 
fun chop () = make_command (fn (_,pairs) => pairs);


435 


436 
(*Restore the previous proof state; discard current state. *)


437 
fun undo() = case !undo_list of


438 
[] => error"No proof state"


439 
 [_] => error"Already at initial state"


440 
 _::newundo => (undo_list := newundo; pr()) ;


441 


442 


443 
(*** Managing the proof stack ***)


444 


445 
fun save_proof() = Proof(!undo_list, !curr_prems, !curr_mkresult);


446 


447 
fun restore_proof(Proof(ul,prems,mk)) =


448 
(undo_list:= ul; curr_prems:= prems; curr_mkresult := mk; prems);


449 


450 


451 
fun top_proof() = case !proofstack of


452 
[] => error("Stack of proof attempts is empty!")


453 
 p::ps => (p,ps);


454 


455 
(* push a copy of the current proof state on to the stack *)


456 
fun push_proof() = (proofstack := (save_proof() :: !proofstack));


457 


458 
(* discard the top proof state of the stack *)


459 
fun pop_proof() =


460 
let val (p,ps) = top_proof()


461 
val prems = restore_proof p


462 
in proofstack := ps; pr(); prems end;


463 


464 
(* rotate the stack so that the top element goes to the bottom *)


465 
fun rotate_proof() = let val (p,ps) = top_proof()


466 
in proofstack := ps@[save_proof()];


467 
restore_proof p;


468 
pr();


469 
!curr_prems


470 
end;


471 


472 


473 
(** Shortcuts for commonlyused tactics **)


474 


475 
fun bws rls = by (rewrite_goals_tac rls);


476 
fun bw rl = bws [rl];


477 


478 
fun brs rls i = by (resolve_tac rls i);


479 
fun br rl = brs [rl];


480 


481 
fun bes rls i = by (eresolve_tac rls i);


482 
fun be rl = bes [rl];


483 


484 
fun bds rls i = by (dresolve_tac rls i);


485 
fun bd rl = bds [rl];


486 


487 
fun ba i = by (assume_tac i);


488 


489 
fun ren str i = by (rename_tac str i);


490 


491 
(** Shortcuts to work on the first applicable subgoal **)


492 


493 
fun frs rls = by (FIRSTGOAL (trace_goalno_tac (resolve_tac rls)));


494 
fun fr rl = frs [rl];


495 


496 
fun fes rls = by (FIRSTGOAL (trace_goalno_tac (eresolve_tac rls)));


497 
fun fe rl = fes [rl];


498 


499 
fun fds rls = by (FIRSTGOAL (trace_goalno_tac (dresolve_tac rls)));


500 
fun fd rl = fds [rl];


501 


502 
fun fa() = by (FIRSTGOAL (trace_goalno_tac assume_tac));


503 


504 


505 
(** theorem database operations **)


506 


507 
(* store *)


508 


509 
fun bind_thm (name, thm) = ThmDatabase.ml_store_thm (name, standard thm);


510 
fun bind_thms (name, thms) = ThmDatabase.ml_store_thms (name, map standard thms);


511 


512 
fun qed name = ThmDatabase.ml_store_thm (name, result ());


513 
fun qed_goal name thy goal tacsf = ThmDatabase.ml_store_thm (name, prove_goal thy goal tacsf);


514 
fun qed_goalw name thy rews goal tacsf =


515 
ThmDatabase.ml_store_thm (name, prove_goalw thy rews goal tacsf);


516 
fun qed_spec_mp name =


517 
ThmDatabase.ml_store_thm (name, ObjectLogic.rulify_no_asm (result ()));


518 
fun qed_goal_spec_mp name thy s p =


519 
bind_thm (name, ObjectLogic.rulify_no_asm (prove_goal thy s p));


520 
fun qed_goalw_spec_mp name thy defs s p =


521 
bind_thm (name, ObjectLogic.rulify_no_asm (prove_goalw thy defs s p));


522 


523 
fun no_qed () = ();


524 


525 


526 
(* retrieve *)


527 


528 
fun thms_containing raw_consts =


529 
let


530 
val thy = Thm.theory_of_thm (topthm ());


531 
val consts = map (Sign.intern_const thy) raw_consts;


532 
in


533 
(case List.filter (is_none o Sign.const_type thy) consts of


534 
[] => ()


535 
 cs => error ("thms_containing: undeclared consts " ^ commas_quote cs));


536 
PureThy.thms_containing_consts thy consts


537 
end;


538 


539 
end;


540 


541 
structure Goals: GOALS = OldGoals;


542 
open Goals;
