(* Title: Pure/Isar/proof.ML Author: Markus Wenzel, TU Muenchen
The Isar/VM proof language interpreter: maintains a structured flow of context elements, goals, refinements, and facts.
*)
signature PROOF = sig type context = Proof.context type method = Method.method type state val init: context -> state val level: state -> int val assert_bottom: bool -> state -> state val context_of: state -> context val theory_of: state -> theory val map_context: (context -> context) -> state -> state val map_context_result : (context -> 'a * context) -> state -> 'a * state val map_contexts: (context -> context) -> state -> state val propagate_ml_env: state -> state val report_improper: state -> unit val the_facts: state -> thm list val the_fact: state -> thm val set_facts: thm list -> state -> state val reset_facts: state -> state val improper_reset_facts: state -> state val assert_forward: state -> state val assert_chain: state -> state val assert_forward_or_chain: state -> state val assert_backward: state -> state val assert_no_chain: state -> state val enter_forward: state -> state val enter_chain: state -> state val enter_backward: state -> state val using_facts: thm list -> state -> state val pretty_state: state -> Pretty.T list val refine: Method.text -> state -> state Seq.result Seq.seq val refine_end: Method.text -> state -> state Seq.result Seq.seq val refine_singleton: Method.text -> state -> state val refine_insert: thm list -> state -> state val refine_primitive: (Proof.context -> thm -> thm) -> state -> state val goal_finished: state -> bool val raw_goal: state -> {context: context, facts: thm list, goal: thm} val goal: state -> {context: context, facts: thm list, goal: thm} val simple_goal: state -> {context: context, goal: thm} val let_bind: (term list * term) list -> state -> state val let_bind_cmd: (stringlist * string) list -> state -> state val write: Syntax.mode -> (term * mixfix) list -> state -> state val write_cmd: Syntax.mode -> (string * mixfix) list -> state -> state val fix: (binding * typ option * mixfix) list -> state -> state val fix_cmd: (binding * stringoption * mixfix) list -> state -> state val assm: Assumption.export -> (binding * typ option * mixfix) list ->
(term * term list) listlist -> (Thm.binding * (term * term list) list) list ->
state -> state val assm_cmd: Assumption.export -> (binding * stringoption * mixfix) list ->
(string * stringlist) listlist -> (Attrib.binding * (string * stringlist) list) list ->
state -> state val assume: (binding * typ option * mixfix) list ->
(term * term list) listlist -> (Thm.binding * (term * term list) list) list ->
state -> state val assume_cmd: (binding * stringoption * mixfix) list ->
(string * stringlist) listlist -> (Attrib.binding * (string * stringlist) list) list ->
state -> state val presume: (binding * typ option * mixfix) list ->
(term * term list) listlist -> (Thm.binding * (term * term list) list) list ->
state -> state val presume_cmd: (binding * stringoption * mixfix) list ->
(string * stringlist) listlist -> (Attrib.binding * (string * stringlist) list) list ->
state -> state val chain: state -> state val chain_facts: thm list -> state -> state val note_thmss: (Thm.binding * (thm list * attribute list) list) list -> state -> state val note_thmss_cmd: (Attrib.binding * (Facts.ref * Token.src list) list) list -> state -> state val from_thmss: ((thm list * attribute list) list) list -> state -> state val from_thmss_cmd: ((Facts.ref * Token.src list) list) list -> state -> state val with_thmss: ((thm list * attribute list) list) list -> state -> state val with_thmss_cmd: ((Facts.ref * Token.src list) list) list -> state -> state val supply: (Thm.binding * (thm list * attribute list) list) list -> state -> state val supply_cmd: (Attrib.binding * (Facts.ref * Token.src list) list) list -> state -> state val using: ((thm list * attribute list) list) list -> state -> state val using_cmd: ((Facts.ref * Token.src list) list) list -> state -> state val unfolding: ((thm list * attribute list) list) list -> state -> state val unfolding_cmd: ((Facts.ref * Token.src list) list) list -> state -> state val case_: Thm.binding * ((string * Position.T) * binding optionlist) -> state -> state val case_cmd: Attrib.binding * ((string * Position.T) * binding optionlist) -> state -> state val define: (binding * typ option * mixfix) list ->
(binding * typ option * mixfix) list ->
(Thm.binding * (term * term list) list) list -> state -> state val define_cmd: (binding * stringoption * mixfix) list ->
(binding * stringoption * mixfix) list ->
(Attrib.binding * (string * stringlist) list) list -> state -> state val begin_block: state -> state val next_block: state -> state val end_block: state -> state val begin_notepad: context -> state val end_notepad: state -> context val is_notepad: state -> bool val reset_notepad: state -> state val proof: Method.text_range option -> state -> state Seq.result Seq.seq val defer: int -> state -> state val prefer: int -> state -> state val apply: Method.text_range -> state -> state Seq.result Seq.seq val apply_end: Method.text_range -> state -> state Seq.result Seq.seq val local_qed: Method.text_range option * bool -> state -> state val theorem: Method.text option -> (thm listlist -> context -> context) ->
(term * term list) listlist -> context -> state val theorem_cmd: Method.text option -> (thm listlist -> context -> context) ->
(string * stringlist) listlist -> context -> state val global_qed: Method.text_range option * bool -> state -> context val schematic_goal: state -> bool val is_relevant: state -> bool val local_terminal_proof: Method.text_range * Method.text_range option -> state -> state val local_default_proof: state -> state val local_immediate_proof: state -> state val local_skip_proof: bool -> state -> state val local_done_proof: state -> state val global_terminal_proof: Method.text_range * Method.text_range option -> state -> context val global_default_proof: state -> context val global_immediate_proof: state -> context val global_skip_proof: bool -> state -> context val global_done_proof: state -> context val internal_goal: (context -> (string * string) * (string * thm list) list -> unit) ->
Proof_Context.mode -> bool -> string -> Method.text option ->
(context * thm listlist -> state -> state) ->
(binding * typ option * mixfix) list ->
(Thm.binding * (term * term list) list) list ->
(Thm.binding * (term * term list) list) list -> state -> thm list * state val have: bool -> Method.text option -> (context * thm listlist -> state -> state) ->
(binding * typ option * mixfix) list ->
(Thm.binding * (term * term list) list) list ->
(Thm.binding * (term * term list) list) list -> bool -> state -> thm list * state val have_cmd: bool -> Method.text option -> (context * thm listlist -> state -> state) ->
(binding * stringoption * mixfix) list ->
(Attrib.binding * (string * stringlist) list) list ->
(Attrib.binding * (string * stringlist) list) list -> bool -> state -> thm list * state val show: bool -> Method.text option -> (context * thm listlist -> state -> state) ->
(binding * typ option * mixfix) list ->
(Thm.binding * (term * term list) list) list ->
(Thm.binding * (term * term list) list) list -> bool -> state -> thm list * state val show_cmd: bool -> Method.text option -> (context * thm listlist -> state -> state) ->
(binding * stringoption * mixfix) list ->
(Attrib.binding * (string * stringlist) list) list ->
(Attrib.binding * (string * stringlist) list) list -> bool -> state -> thm list * state val future_proof: (state -> ('a * context) future) -> state -> 'a future * state val local_future_terminal_proof: Method.text_range * Method.text_range option -> state -> state val global_future_terminal_proof: Method.text_range * Method.text_range option -> state -> context end;
structure Proof: PROOF = struct
type context = Proof.context; type method = Method.method;
(** proof state **)
(* datatype state *)
datatype mode = Forward | Chain | Backward;
datatype state =
State of node Stack.T and node =
Node of
{context: context,
facts: (thm list * bool) option,
mode: mode,
goal: goal option} and goal =
Goal of
{statement: (string * Position.T) * term listlist * term, (*goal kind and statement (starting with vars), initial proposition*)
using: thm list, (*goal facts*)
goal: thm, (*subgoals \<Longrightarrow> statement*)
before_qed: Method.text option,
after_qed:
(context * thm listlist -> state -> state) *
(context * thm listlist -> context -> context)};
val _ =
ML_system_pp (fn _ => fn _ => fn _: state => ML_Pretty.str "");
fun map_node f (Node {context, facts, mode, goal}) =
make_node (f (context, facts, mode, goal));
val init_context =
Proof_Context.set_stmt true #>
Proof_Context.map_naming (K Name_Space.local_naming);
fun init ctxt =
State (Stack.init (make_node (init_context ctxt, NONE, Forward, NONE)));
fun top (State stack) = Stack.top stack |> (fn Node node => node); fun map_top f (State stack) = State (Stack.map_top (map_node f) stack); fun map_all f (State stack) = State (Stack.map_all (map_node f) stack);
(** basic proof state operations **)
(* block structure *)
fun open_block (State stack) = State (Stack.push stack);
fun close_block (State stack) = State (Stack.pop stack) handleList.Empty => error "Unbalanced block parentheses";
fun level (State stack) = Stack.level stack;
fun assert_bottom b state = letval b' = level state <= 2 in if b andalso not b' then error "Not at bottom of proof" elseifnot b andalso b' then error "Already at bottom of proof" else state end;
(* context *)
val context_of = #context o top; val theory_of = Proof_Context.theory_of o context_of;
fun map_context f =
map_top (fn (ctxt, facts, mode, goal) => (f ctxt, facts, mode, goal));
fun map_context_result f state =
f (context_of state) ||> (fn ctxt => map_context (K ctxt) state);
fun map_contexts f = map_all (fn (ctxt, facts, mode, goal) => (f ctxt, facts, mode, goal));
fun propagate_ml_env state = map_contexts
(Context.proof_map (ML_Env.inherit [Context.Proof (context_of state)])) state;
(* facts *)
fun report_improper state =
Context_Position.report (context_of state) (Position.thread_data ()) Markup.improper;
val get_facts = #facts o top;
fun the_facts state =
(case get_facts state of
SOME (facts, proper) => (if proper then () else report_improper state; facts)
| NONE => error "No current facts available");
fun the_fact state =
(case the_facts state of
[thm] => thm
| _ => error "Single theorem expected");
fun put_facts index facts =
map_top (fn (ctxt, _, mode, goal) => (ctxt, facts, mode, goal)) #>
map_context (Proof_Context.put_thms index (Auto_Bind.thisN, Option.map #1 facts));
fun set_facts thms = put_facts false (SOME (thms, true)); val reset_facts = put_facts false NONE;
fun improper_reset_facts state =
(case get_facts state of
SOME (thms, _) => put_facts false (SOME (thms, false)) state
| NONE => state);
fun these_factss more_facts (named_factss, state) =
(named_factss, state |> set_facts (maps snd named_factss @ more_facts));
fun export_facts inner outer =
(case get_facts inner of
NONE => reset_facts outer
| SOME (thms, proper) => letval thms' = Proof_Context.export (context_of inner) (context_of outer) thms in put_facts true (SOME (thms', proper)) outer end);
(* mode *)
val get_mode = #mode o top; fun put_mode mode = map_top (fn (ctxt, facts, _, goal) => (ctxt, facts, mode, goal));
fun assert_mode pred state = letval mode = get_mode state in if pred mode then state else error ("Illegal application of proof command in " ^ quote (mode_name mode) ^ " mode") end;
val enter_forward = put_mode Forward; val enter_chain = put_mode Chain; val enter_backward = put_mode Backward;
(* current goal *)
fun current_goal state =
(case top state of
{context = ctxt, goal = SOME (Goal goal), ...} => (ctxt, goal)
| _ => error "No current goal");
fun assert_current_goal g state = letval g' = can current_goal state in if g andalso not g' then error "No goal in this block" elseifnot g andalso g' then error "Goal present in this block" else state end;
val set_goal = put_goal o SOME; val reset_goal = put_goal NONE;
val before_qed = #before_qed o #2 o current_goal;
(* nested goal *)
fun map_goal f (State stack) =
(case Stack.dest stack of
(Node {context = ctxt, facts, mode, goal = SOME goal}, node :: nodes) => let val Goal {statement, using, goal, before_qed, after_qed} = goal; val (ctxt', statement', using', goal', before_qed', after_qed') =
f (ctxt, statement, using, goal, before_qed, after_qed); val goal' = make_goal (statement', using', goal', before_qed', after_qed'); in State (Stack.make (make_node (ctxt', facts, mode, SOME goal')) (node :: nodes)) end
| (top_node, node :: nodes) => let val State stack' = map_goal f (State (Stack.make node nodes)); val (node', nodes') = Stack.dest stack'; in State (Stack.make top_node (node' :: nodes')) end
| _ => State stack);
fun pretty_state state = let val {context = ctxt, facts, mode, goal = _} = top state; val verbose = Config.get ctxt Proof_Context.verbose;
val prt_facts = Proof_Display.pretty_goal_facts ctxt;
fun prt_goal (SOME (_, goal)) = let val {statement = (_, propss, _), using, goal, before_qed = _, after_qed = _} = goal; val head = [Proof_Display.pretty_goal_header goal]; val body = Goal_Display.pretty_goals ctxt goal; val foot = Proof_Display.pretty_goal_inst ctxt propss goal; in
pretty_sep
(prt_facts "using" (if mode <> Backward orelse null using then NONE else SOME using))
(head @ body @ foot) end
| prt_goal NONE = [];
val prt_ctxt = if verbose orelse mode = Forward then Proof_Context.pretty_context ctxt elseif mode = Backward then Proof_Context.pretty_ctxt ctxt else [];
fun apply_method text ctxt state =
find_goal state |> (fn (goal_ctxt, {statement, using, goal, before_qed, after_qed}) =>
Method.evaluate text ctxt using (goal_ctxt, goal)
|> Seq.map_result (fn (goal_ctxt', goal') =>
state |> map_goal (K (goal_ctxt', statement, using, goal', before_qed, after_qed))));
in
fun refine text state = apply_method text (context_of state) state; fun refine_end text state = apply_method text (#1 (find_goal state)) state;
fun refine_singleton text = refine text #> Seq.the_result "";
fun refine_insert ths =
refine_singleton (Method.Basic (K (Method.insert ths)));
fun refine_primitive r =
refine_singleton (Method.Basic (fn ctxt => fn _ => CONTEXT_TACTIC (PRIMITIVE (r ctxt))));
end;
(* refine via sub-proof *)
local
fun finish_tac _ 0 = K all_tac
| finish_tac ctxt n =
Goal.norm_hhf_tac ctxt THEN'
SUBGOAL (fn (goal, i) => if can Logic.unprotect (Logic.strip_assums_concl goal) then
eresolve_tac ctxt [Drule.protectI] i THEN finish_tac ctxt (n - 1) i else finish_tac ctxt (n - 1) (i + 1));
fun finished_goal pos state = letval (ctxt, {goal, ...}) = find_goal state in if Thm.no_prems goal then Seq.Result state else
Seq.Error (fn () =>
Pretty.string_of (Pretty.chunks
[finished_goal_error_pos pos, Proof_Display.pretty_goal ctxt goal])) end;
(* goal views -- corresponding to methods *)
val goal_finished = Thm.no_prems o #goal o #2 o find_goal;
fun raw_goal state = letval (ctxt, {using, goal, ...}) = find_goal state in {context = ctxt, facts = using, goal = goal} end;
val goal = raw_goal o refine_insert [];
fun simple_goal state = let val (_, {using, ...}) = find_goal state; val (ctxt, {goal, ...}) = find_goal (refine_insert using state); in {context = ctxt, goal = goal} end;
fun method_error kind pos state =
Seq.single (Proof_Display.method_error kind pos (raw_goal state));
(*** structured proof commands ***)
(** context elements **)
(* let bindings *)
local
fun gen_bind prep_terms raw_binds =
assert_forward #> map_context (fn ctxt => let fun prep_bind (raw_pats, t) ctxt1 = let val T = Term.fastype_of t; val ctxt2 = Variable.declare_term t ctxt1; val pats = prep_terms (Proof_Context.set_mode Proof_Context.mode_pattern ctxt2) T raw_pats; val binds = Proof_Context.simult_matches ctxt2 (t, pats); in (binds, ctxt2) end;
val note_thmss = gen_thmss (K []) I #2 (K I) (K I); val note_thmss_cmd = gen_thmss (K []) I #2 Attrib.attribute_cmd Proof_Context.get_fact;
val from_thmss = gen_thmss (K []) chain #2 (K I) (K I) o empty_bindings; val from_thmss_cmd =
gen_thmss (K []) chain #2 Attrib.attribute_cmd Proof_Context.get_fact o empty_bindings;
val with_thmss = gen_thmss the_facts chain #2 (K I) (K I) o empty_bindings; val with_thmss_cmd =
gen_thmss the_facts chain #2 Attrib.attribute_cmd Proof_Context.get_fact o empty_bindings;
val local_results = gen_thmss (K []) I I (K I) (K I) o map (apsnd Thm.simple_fact);
end;
(* facts during goal refinement *)
local
fun gen_supply prep_att prep_fact args state =
state
|> assert_backward
|> map_context (fn ctxt => ctxt |> Proof_Context.note_thmss ""
(Attrib.map_facts_refs (map (prep_att ctxt)) (prep_fact ctxt) args) |> snd);
in
val supply = gen_supply (K I) (K I); val supply_cmd = gen_supply Attrib.attribute_cmd Proof_Context.get_fact;
end;
(* using/unfolding *)
local
fun gen_using f g prep_att prep_fact args state =
state
|> assert_backward
|> map_context_result
(fn ctxt => ctxt |> Proof_Context.note_thmss ""
(Attrib.map_facts_refs (map (prep_att ctxt)) (prep_fact ctxt) (empty_bindings args)))
|> (fn (named_facts, state') =>
state' |> map_goal (fn (goal_ctxt, statement, using, goal, before_qed, after_qed) => let val ctxt = context_of state'; val ths = maps snd named_facts; in (goal_ctxt, statement, f ctxt ths using, g ctxt ths goal, before_qed, after_qed) end));
fun append_using _ ths using = using @ filter_out Thm.is_dummy ths; fun unfold_using ctxt ths = map (Local_Defs.unfold ctxt ths); val unfold_goals = Local_Defs.unfold_goals;
in
val using = gen_using append_using (K (K I)) (K I) (K I); val using_cmd = gen_using append_using (K (K I)) Attrib.attribute_cmd Proof_Context.get_fact; val unfolding = gen_using unfold_using unfold_goals (K I) (K I); val unfolding_cmd = gen_using unfold_using unfold_goals Attrib.attribute_cmd Proof_Context.get_fact;
end;
(* case *)
local
fun gen_case internal prep_att ((raw_binding, raw_atts), ((name, pos), xs)) state = let val ctxt = context_of state;
val binding = if Binding.is_empty raw_binding then Binding.make (name, pos) else raw_binding; val atts = map (prep_att ctxt) raw_atts;
val is_var =
can (dest_TVar o Logic.dest_type o Logic.dest_term) orf
can (dest_Var o Logic.dest_term);
fun implicit_vars props = let val var_props = take_prefix is_var props; val explicit_vars = fold Term.add_vars var_props []; in
fold Term.add_vars props [] |> map_filter (fn v => if member (op =) explicit_vars v then NONE else SOME (Logic.mk_term (Var v))) end;
fun refine_terms n =
refine_singleton (Method.Basic (fn ctxt => CONTEXT_TACTIC o
K (HEADGOAL (PRECISE_CONJUNCTS n
(HEADGOAL (CONJUNCTS (ALLGOALS (resolve_tac ctxt [Drule.termI]))))))));
in
fun generic_goal kind before_qed after_qed goal_ctxt goal_propss result_binds state = let val chaining = can assert_chain state; val pos = Position.thread_data ();
val goal_props = flat goal_propss; val goal_vars = implicit_vars goal_props; val propss' = goal_vars :: goal_propss; val goal_propss' = filter_out null propss';
fun generic_qed state = let val (goal_ctxt, goal_config) = current_goal state; val {statement = (_, propss, _), goal, after_qed, ...} = goal_config; val results = tl (conclude_goal goal_ctxt goal propss); val res =
{goal_ctxt = goal_ctxt,
goal_config = goal_config,
after_qed = after_qed,
results = results}; in state |> close_block |> pair res end;
end;
(* local goals *)
fun local_goal print_results prep_statement prep_att strict_asm
kind before_qed after_qed raw_fixes raw_assumes raw_shows state = let val ctxt = context_of state;
val add_assumes =
Assumption.add_assms
(if strict_asm then Assumption.assume_export else Assumption.presume_export);
fun schematic_goal state = letval (_, {statement = (_, _, prop), ...}) = find_goal state in Term.is_schematic prop end;
fun is_relevant state =
(casetry find_goal state of
NONE => true
| SOME (_, {statement = (_, _, prop), goal, ...}) =>
Term.is_schematic prop orelse not (Logic.protect prop aconv Thm.concl_of goal));
(* terminal proof steps *)
local
fun terminal_proof qeds initial terminal state = let val ctxt = context_of state; val check_closure = Method.check_text ctxt #> Method.map_source (Method.method_closure ctxt); val initial' = apfst check_closure initial; val terminal' = (apfst o Option.map o apfst) check_closure terminal; in if Goal.skip_proofs_enabled () andalso not (is_relevant state) then
state
|> proof (SOME (Method.sorry_text true, #2 initial'))
|> Seq.maps_results (qeds (#2 (#2 initial), (NONE, #2 terminal))) else
state
|> proof (SOME initial')
|> Seq.maps_results (qeds (#2 (#2 initial), terminal')) end |> Seq.the_result "";
in
fun local_terminal_proof (text, opt_text) = terminal_proof local_qeds text (opt_text, true); val local_default_proof = local_terminal_proof ((Method.standard_text, Position.no_range), NONE); val local_immediate_proof = local_terminal_proof ((Method.this_text, Position.no_range), NONE); val local_done_proof = terminal_proof local_qeds (Method.done_text, Position.no_range) (NONE, false);
fun global_terminal_proof (text, opt_text) =
terminal_proof global_qeds text (opt_text, true) #> global_goal_inst; val global_default_proof = global_terminal_proof ((Method.standard_text, Position.no_range), NONE); val global_immediate_proof = global_terminal_proof ((Method.this_text, Position.no_range), NONE); val global_done_proof =
terminal_proof global_qeds (Method.done_text, Position.no_range) (NONE, false) #> global_goal_inst;
end;
(* skip proofs *)
fun local_skip_proof int state =
local_terminal_proof ((Method.sorry_text int, Position.no_range), NONE) state before
Skip_Proof.report (context_of state);
fun global_skip_proof int state =
global_terminal_proof ((Method.sorry_text int, Position.no_range), NONE) state before
Skip_Proof.report (context_of state);
(* common goal statements *)
fun internal_goal print_results mode =
local_goal print_results
(fn a => fn b => fn c => Proof_Context.cert_statement a b c o Proof_Context.set_mode mode) (K I);
fun gen_show prep_statement prep_att strict_asm before_qed after_qed fixes assumes shows int state = let val testing = Unsynchronized.reffalse; val rule = Unsynchronized.ref (NONE: thm option); fun fail_msg ctxt = "Local statement fails to refine any pending goal" ::
(case ! rule of NONE => [] | SOME th => [Proof_Display.string_of_rule ctxt "Failed" th])
|> cat_lines;
fun print_results ctxt res = if ! testing then () else Proof_Display.print_results {interactive = int, pos = Position.thread_data ()} ctxt res; fun print_rule ctxt th = if ! testing then rule := SOME th elseif int then
Proof_Display.string_of_rule ctxt "Successful" th
|> Markup.markup Markup.text_fold
|> Output.writeln_urgent else (); val test_proof =
local_skip_proof true
|> Unsynchronized.setmp testing true
|> Exn.result;
fun after_qed' (result_ctxt, results) state' = state'
|> refine_goals print_rule result_ctxt (flat results)
|> check_result "Failed to refine any pending goal"
|> after_qed (result_ctxt, results); in
state
|> local_goal print_results prep_statement prep_att strict_asm "show" before_qed after_qed' fixes assumes shows
||> int ? (fn goal_state =>
(case test_proof (map_context (Context_Position.set_visible false) goal_state) of
Exn.Res _ => goal_state
| Exn.Exn exn => raise Exn.EXCEPTIONS ([exn, ERROR (fail_msg (context_of goal_state))]))) end;
in
val have = gen_have Proof_Context.cert_statement (K I); val have_cmd = gen_have Proof_Context.read_statement Attrib.attribute_cmd; val show = gen_show Proof_Context.cert_statement (K I); val show_cmd = gen_show Proof_Context.read_statement Attrib.attribute_cmd;
end;
(** future proofs **)
(* full proofs *)
local
structure Result = Proof_Data
( type T = thm option; fun init _ = NONE;
);
fun the_result ctxt =
Result.get ctxt |> \<^if_none>\<open>error "No result of forked proof"\<close>;
val set_result = Result.put o SOME; val reset_result = Result.put NONE;
in
fun future_proof fork_proof state = let val _ = assert_backward state; val (goal_ctxt, goal) = find_goal state; val {statement as (kind, _, prop), using, goal, before_qed, after_qed} = goal;
val _ = is_relevant state andalso error "Cannot fork relevant proof";
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.