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 block/3 and exit_block/1.

block(Goal, BTag, Recovery)

like call(Goal), except that in addition a Recovery goal is set up, which can be called by exit_block from anywhere inside the call to Goal. When exit_block(ETag) is called, then if ETag unifies with a BTag from an enclosing block, the recovery goal associated with that block is called, with the system immediately failing back to where the block was called. In addition, ETag can be used to pass information to the recovery goal, if BTag occurs as an argument of Recovery.
exit_block(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 block/3, any irregular termination can be caught and handled, e.g.

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

main(X,Y,Z) :-
    ...,
    ( test(...) -> ... ; exit_block(test_failed) ),
    ...,
When built-in predicates raise errors, this results in the predicate being exited with the tag abort, which can also be caught:

?- block(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