By wrapping a predicate call into block/3, any irregular termination can be caught and handled, e.g.
- 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
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) ), ..., |
abort
, which can also be caught:
Note that timeouts and stack overflows also lead to exits and can be caught this way.?- block(X is 1//0, T, true). arithmetic exception in //(1, 0, X) X = X T = abort Yes (0.00s cpu)