Next: ref-ere-hex-hup, Up: ref-ere-hex [Contents][Index]
The built-in predicate catch/3
enables you to handle
exceptions to a specific goal:
catch(:ProtectedGoal, ?ExceptionTerm, :Handler) ISO
ProtectedGoal is executed. If all goes well, then it will behave just
as if you had written call(ProtectedGoal)
instead. If an
exception is thrown while ProtectedGoal is running, then Prolog will
abandon ProtectedGoal entirely. Any bindings made by
ProtectedGoal will be undone, just as if it had failed. If the
exception occurred in the scope of a
call_cleanup(Goal,Cleanup)
, then Cleanup will be
called.
side effects, such as asserts and retracts,
are not undone, just as they are not undone when a goal fails. After
undoing the bindings, Prolog tries to unify the exception term thrown
with the ExceptionTerm argument. If this unification succeeds, then
Handler will be executed as if you had written
ExceptionTerm=<the actual exception term>, Handler
If this unification fails, then Prolog will keep searching up the ancestor
list looking for another exception handler. If during this search it
reaches a recursive call to Prolog from C, then the recursive calls returns
with an uncaught exception. If it reaches the top level (or a break
level), then an appropriate error message is printed (using
print_message/2
).
ProtectedGoal need not be determinate. That is, backtracking into
ProtectedGoal is possible, and the exception handler becomes reactivated
in this case. However, if ProtectedGoal is determinate, then the call
to catch/3
is also determinate.
The ProtectedGoal is logically inside the catch/3
goal, but the Handler is not. If an exception is thrown inside
the Handler, then this catch/3
goal will not be
reactivated. If you want an exception handler that protects itself, then
you have to program it, perhaps like this:
recursive_catch_handler(Err, Goal, Handler) :- catch(Goal, Err, recursive_catch_handler(Err, Handler, Handler)).
See mpg-ref-catch.
Certain built-in and library predicates rely on the exception mechanism, so it is usually a bad idea to let Pattern be a variable, matching any exception. If it must be a variable, then the Handler should examine the exception and pass it on if it is not relevant to the current invocation.