on_exception(-Exception, +*ProtectedGoal, +*Handler
Specify an exception handler for ProtectedGoal, and call ProtectedGoal.
ProtectedGoal is executed. This will
behave just as if ProtectedGoal had been written without the
on_exception/3 wrapper. If ProtectedGoal is determinate,
on_exception/3 will also be determinate.
ProtectedGoal can also be nondeterminate. As a general rule,
code is easier to read when ProtectedGoal is a simple goal,
however a conjunction of goals (Goal1,...GoalN) or any other form that
call/1 accepts is allowed.
If an exception is raised while ProtectedGoal is running, Prolog will abandon ProtectedGoal entirely. Any bindings made by ProtectedGoal will be undone, just as if it had failed. Side effects, such as data-base changes and input/output, are not undone, just as they are not undone when a goal fails. After undoing the bindings, Prolog then tries to unify an object called an exception term with the Exception argument. If this unification succeeds, Handler will be executed as if you had written
Exception=the actual exception term, Handler
If this unification fails, Prolog will keep looking for a handler. It will always find a handler at the top level, which prints out a message corresponding to the exception.
In applications lacking a top level (C calling Prolog, where
QP_toplevel() has not been called) exceptions are indicated by
the return status
QP_ERROR. For more details refer to
More efficient code is generated when ProtectedGoal
is a simple goal. In other cases, such as where ProtectedGoal is a
conjunction of goals (Goal1,...GoalN), the compiler treats this as if
)). This potential inefficiency does
not apply to Handler.
Fail on exception:
:-meta_predicate fail_on_exception/1. fail_on_exception(C):- on_exception(E,C,print_exception_then_fail(C,E)). print_exception_then_fail(C,E):- format('Exception occured while calling ~q:~n', [C]), print_message(warning,E), fail.