Protecting a Particular Goal

The built-in predicate on_exception/3 enables you to handle exceptions to a specific goal:

on_exception(?ExceptionCode, +ProtectedGoal, +Handler)

ProtectedGoal is executed. If all goes well, it will behave just as if you had written ProtectedGoal without the on_exception/3 wrapper. 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 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 code raised with the ExceptionCode argument. If this unification succeeds, Handler will be executed as if you had written

     
     ExceptionCode=<the actual exception code>,
     Handler
     

If this unification fails, Prolog will keep searching up the ancestor list looking for another exception handler. If it reaches Prolog's top level (or a break level) without having found a call to on_exception/3 with a matching ExceptionCode, 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 on_exception/3 is also determinate.

Setting up an exception handler with on_exception/3 is cheap provided that ProtectedGoal is an ordinary goal. Some efficiency is lost, in the current implementation, if ProtectedGoal is of the form (Goal1,Goal2) or (Goal1;Goal2).

The ProtectedGoal is logically inside the on_exception/3 form, but the Handler is not. If an exception is raised inside the Handler, this on_exception/3 form will not be reactivated. If you want an exception handler that protects itself, you have to program it, perhaps like this:

     recursive_on_exception_handler(Err, Goal, Handler) :-
         on_exception(Err, Goal,
             recursive_on_exception_handler(Err, Handler, Handler)).