Previous Up Next

4.11  Exception Handling

It is sometimes necessary to exit prematurely from an executing procedure, for example because some situation was detected which makes continuing impossible. In this situation, one wants to return to some defined state and perform some kind of recovery action. This functionality is provided by catch/3 and throw/1 (formerly known as block/3 and exit_block/1).


catch(Goal, BTag, Recovery)

like call(Goal), except that in addition a Recovery goal is set up, which can be called by throw from anywhere inside the call to Goal. When throw(ETag) is called, then if ETag unifies with a BTag from an enclosing block, the recovery goal associated with that catch is called, with the system immediately failing back to where the catch was called. In addition, ETag can be used to pass information to the recovery goal, if BTag occurs as an argument of Recovery.
throw(ETag)

will transfer control to the innermost enclosing block/3 whose BTag argument unifies with ETag.
Figure 4.6: Exception Handling

By wrapping a predicate call into catch/3, any irregular termination can be caught and handled, e.g.

protected_main(X,Y,Z) :-
    catch(
        main(X,Y,Z),
        Problem,
        printf("Execution of main/3 aborted with %w%n", [Problem])
    ).

main(X,Y,Z) :-
    ...,
    ( test(...) -> ... ; throw(test_failed) ),
    ...,

When built-in predicates raise errors, this results in the predicate being exited with the tag abort, which can also be caught:

?- catch(X is 1//0, T, true).
arithmetic exception in //(1, 0, X)
X = X
T = abort
Yes (0.00s cpu)

Note that timeouts and stack overflows also lead to exits and can be caught this way.


Previous Up Next