The following is small prolog meta-interpreter that interprets the cut using the catch/throw mechanism[1].
fruit(apple).
fruit(orange) :- !.
fruit(banana).
% meta-interpreter that handles the cut
prove(true) :- !.
prove(!) :- !, ( true ; throw(cut) ).
prove((A,B)):- !, prove(A), prove(B).
prove(H) :-
catch((clause(H,B), prove(B)), cut, fail).
With plain prolog:
?- fruit(X).
X = apple
X = orange
... and with the meta-interpreter, the results are as expected:
?- prove(fruit(X)).
X = apple
X = orange
Question
My question is about retention of choices made within the scope of catch(Goal, ExceptionTag, Handler)
.
Q1: The SWI-Prolog documentation for catch/3
[2] is not clear. But it suggests that all choices made inside Goal are discarded when an exception is raised. This, to me, doesn't accord with the observed behaviour. If all choices are lost, then prove(!):-true
would not remain committed to, which would then not result in X=orange
as a solution.
What am I misunderstanding about the behaviour of catch/3
?
Q2: Even if the choices are retained, the effect of Handler=fail
means the entire scope ((clause(H,B), prove(B))
should fail, again disgarding any choices made in that Goal
.
Clearly I am misunderstanding something here.
My Attempt At Diagnosis
I changed the meta-interpreter to be more verbose at the areas of interest:
prove(!) :- writeln("111"), true.
prove(!) :- writeln("222"), throw(cut), writeln("333").
The output confirms that the choice associated with prove(!)-writeln("111"),true
is retained - apparently in contradiction with the documentation.
?- prove(fruit(X)),
X = apple
111
222
X = orange
In addition to SWI-Prolog I've googled the documentation of implementations and they aren't clear either.
UPDATE:
Given the comments I am highlighting the SWI-Prolog documentation for catch/3
:
all choice points generated by Goal are cut, the system backtracks to the start of catch/3
This suggests that all solutions are lost, as if the Goal in catch(Goal, Exception, Handler)
was not executed.