more informative error messages of initial/terminal proof methods;
authorwenzelm
Tue, 16 Oct 2012 13:06:40 +0200
changeset 49859 52da6a736c32
parent 49858 4a15873c4ec9
child 49860 9a0fe50e4534
more informative error messages of initial/terminal proof methods; more systematic support for sequences with embedded errors; tuned Seq.maps;
src/Pure/General/seq.ML
src/Pure/Isar/proof.ML
--- a/src/Pure/General/seq.ML	Mon Oct 15 19:03:02 2012 +0200
+++ b/src/Pure/General/seq.ML	Tue Oct 16 13:06:40 2012 +0200
@@ -35,6 +35,11 @@
   val singleton: ('a list -> 'b list seq) -> 'a -> 'b seq
   val print: (int -> 'a -> unit) -> int -> 'a seq -> unit
   val it_right : ('a * 'b seq -> 'b seq) -> 'a seq * 'b seq -> 'b seq
+  datatype 'a result = Result of 'a | Error of unit -> string
+  val maps_results: ('a -> 'b result seq) -> 'a result seq -> 'b result seq
+  val maps_result: ('a -> 'b seq) -> 'a result seq -> 'b result seq
+  val map_result: ('a -> 'b) -> 'a result seq -> 'b result seq
+  val the_result: string -> 'a result seq -> 'a
   val succeed: 'a -> 'a seq
   val fail: 'a -> 'b seq
   val THEN: ('a -> 'b seq) * ('b -> 'c seq) -> 'a -> 'c seq
@@ -110,7 +115,7 @@
 fun of_list xs = fold_rev cons xs empty;
 
 
-(*sequence append:  put the elements of xq in front of those of yq*)
+(*sequence append: put the elements of xq in front of those of yq*)
 fun append xq yq =
   let
     fun copy s =
@@ -161,7 +166,12 @@
       NONE => NONE
     | SOME (x, xq') => SOME (f x, map f xq')));
 
-fun maps f = flat o map f;
+fun maps f xq =
+  make (fn () =>
+    (case pull xq of
+      NONE => NONE
+    | SOME (x, xq') => pull (append (f x) (maps f xq'))));
+
 fun map_filter f = maps (fn x => (case f x of NONE => empty | SOME y => single y));
 
 fun lift f xq y = map (fn x => f x y) xq;
@@ -191,6 +201,33 @@
   in its xq end;
 
 
+(* embedded errors *)
+
+datatype 'a result = Result of 'a | Error of unit -> string;
+
+fun maps_results f xq =
+  make (fn () =>
+    (case pull xq of
+      NONE => NONE
+    | SOME (Result x, xq') => pull (append (f x) (maps_results f xq'))
+    | SOME (Error msg, xq') => SOME (Error msg, maps_results f xq')));
+
+fun maps_result f = maps_results (map Result o f);
+fun map_result f = maps_result (single o f);
+
+(*first result or first error within sequence*)
+fun the_result default_msg seq =
+  let
+    fun result opt_msg xq =
+      (case (opt_msg, pull xq) of
+        (_, SOME (Result x, _)) => x
+      | (SOME _, SOME (Error _, xq')) => result opt_msg xq'
+      | (NONE, SOME (Error msg, xq')) => result (SOME msg) xq'
+      | (SOME msg, NONE) => error (msg ())
+      | (NONE, NONE) => error (if default_msg = "" then "Empty result sequence" else default_msg));
+  in result NONE seq end;
+
+
 
 (** sequence functions **)      (*cf. Pure/tactical.ML*)
 
--- a/src/Pure/Isar/proof.ML	Mon Oct 15 19:03:02 2012 +0200
+++ b/src/Pure/Isar/proof.ML	Tue Oct 16 13:06:40 2012 +0200
@@ -514,20 +514,16 @@
       | recover_result _ _ = lost_structure ();
   in recover_result propss results end;
 
-fun the_finished_goal results =
-  (case Seq.pull results of
-    SOME ((f1, state1), rest) =>
-      let val (ctxt1, (_, goal1)) = get_goal state1 in
-        if Thm.no_prems goal1 then f1 state1
-        else
-          (case Seq.pull (Seq.filter (Thm.no_prems o #2 o #2 o get_goal o #2) rest) of
-            SOME ((f, state), _) => f state
-          | NONE =>
-              error ("Failed to finish proof:\n" ^
-                Pretty.string_of
-                  (Goal_Display.pretty_goal {main = true, limit = false} ctxt1 goal1)))
-      end
-  | NONE => error "Failed to finish proof");
+val finished_goal_error = "Failed to finish proof";
+
+fun finished_goal state =
+  let val (ctxt, (_, goal)) = get_goal state in
+    if Thm.no_prems goal then Seq.Result state
+    else
+      Seq.Error (fn () =>
+        finished_goal_error ^ ":\n" ^
+          Pretty.string_of (Goal_Display.pretty_goal {main = true, limit = false} ctxt goal))
+  end;
 
 
 (* goal views -- corresponding to methods *)
@@ -833,7 +829,8 @@
   |> assert_current_goal true
   |> using_facts []
   |> `before_qed |-> (refine o the_default Method.succeed_text)
-  |> Seq.maps (refine (Method.finish_text txt));
+  |> Seq.maps (refine (Method.finish_text txt))
+  |> Seq.map finished_goal;
 
 fun check_result msg sq =
   (case Seq.pull sq of
@@ -954,10 +951,10 @@
 
 fun local_qeds txt =
   end_proof false txt
-  #> Seq.map (pair (generic_qed Proof_Context.auto_bind_facts #->
-    (fn ((after_qed, _), results) => after_qed results)));
+  #> Seq.map_result (generic_qed Proof_Context.auto_bind_facts #->
+    (fn ((after_qed, _), results) => after_qed results));
 
-fun local_qed txt = local_qeds txt #> the_finished_goal;
+fun local_qed txt = local_qeds txt #> Seq.the_result finished_goal_error;
 
 
 (* global goals *)
@@ -975,33 +972,34 @@
 
 fun global_qeds txt =
   end_proof true txt
-  #> Seq.map (pair (generic_qed (K I) #> (fn (((_, after_qed), results), state) =>
-    after_qed results (context_of state))));
+  #> Seq.map_result (generic_qed (K I) #> (fn (((_, after_qed), results), state) =>
+    after_qed results (context_of state)));
 
-fun global_qed txt = global_qeds txt #> the_finished_goal;
+fun global_qed txt = global_qeds txt #> Seq.the_result finished_goal_error;
 
 
 (* concluding steps *)
 
-local
-
-fun failure_initial state =
+fun method_error name state = Seq.Error (fn () =>
   let
     val (ctxt, (facts, goal)) = get_goal state;
+    val pr_header =
+      "Failure of " ^ (if name = "" then "" else name ^ " ") ^ "proof method on goal state:\n";
     val pr_facts =
       if null facts then ""
       else Pretty.string_of (Pretty.big_list "facts:" (map (Display.pretty_thm ctxt) facts)) ^ "\n";
     val pr_goal =
       "goal:\n" ^ Pretty.string_of (Goal_Display.pretty_goal {main = false, limit = false} ctxt goal);
-  in error ("Failure of initial proof method on goal state:\n" ^ pr_facts ^ pr_goal) end;
+  in pr_header ^ pr_facts ^ pr_goal end);
 
-fun failure_terminal _ = error "Failure of terminal proof method";
+local
 
-val op ORELSE = Seq.ORELSE;
+val op APPEND = Seq.APPEND;
 
 fun terminal_proof qeds initial terminal =
-  (((proof (SOME initial) ORELSE failure_initial)
-    #> Seq.maps (qeds terminal)) ORELSE failure_terminal) #> the_finished_goal;
+  ((proof (SOME initial) #> Seq.map Seq.Result) APPEND (Seq.single o method_error "initial"))
+  #> Seq.maps_results (qeds terminal APPEND (Seq.single o method_error "terminal"))
+  #> Seq.the_result "";
 
 in