The ISO / IEC Prolog standard provides only a very rudimentary mechanism for handling exceptions and errors, which is more or less comparable to what Java offers, and far from it. General Lisp is a rich mechanism, but there are still some points worth noting. In particular, in addition to the real signaling and processing mechanism, many systems provide a mechanism similar to unwind-protect . That is, a way to ensure that the goal will be fulfilled even if there are unprocessed signals.
ISO throw / 1, catch / 3
An exception is thrown / thrown using throw(Term) . First, a copy of Term is created using copy_term/2 , which calls its Termcopy , and then this new copy is used to find the corresponding catch(Goal, Pattern, Handler) , the second argument of which is combined with Termcopy . When the Handler is executed, all unifications caused by Goal are canceled. Thus, for Handler there is no access to the lookups that are present when throw/1 executed. And there is no way to continue working in the place where throw/1 was executed.
Errors of built-in predicates are signaled by running throw(error(Error_term, Imp_def)) , where Error_term corresponds to one of the ISO error classes and Imp_def can provide the implementation of certain additional information (for example, the source file, line number, etc.).
There are many cases where error handling locally would be very useful, but many developers find it too complicated to implement.
The extra effort that the Prolog processor handles every local error is pretty significant and much more so than in Common Lisp or other programming languages. This is due to the very nature of the association in Prolog. Local error handling would require the cancellation of unifications that are performed during the execution of the built-in: the implementation has two possibilities for implementing this:
- create a “selection point” at the time of invoking the built-in predicate, this entails a lot of additional overhead, both for creating this selection point and the “back” subsequent bindings
- execute each built-in predicate manually and decide in each case to handle errors - while this is the most efficient in terms of execution time overhead, it is also the most expensive and error-prone approach
Similar difficulties are caused by the use of WAM registers inside the built-in modules. Again, there is a choice between a slow system or one with significant overhead.
exception_handler / 3
Many systems, however, provide internal mechanisms, but only a few offer them sequentially to the programmer. IF / Prolog provides exception_handler/3 , which has the same arguments as catch/3 , but handles the error or exception locally:
[user]? - catch ((arg (a, f (1), _); Z = ok), error (type_error (_, _), _), fail).
no
[user]? - exception_handler ((arg (a, f (1), _); Z = ok), error (type_error (_, _), _), fail).
Z = ok
yes
setup_call_cleanup / 3
This built-in module offers many systems. It is very similar to unwind-protect , but requires some additional complexity due to the Prolog backtracking mechanism. See His current definition .
All these mechanisms must be provided by the Implementor system; they cannot be built on top of the ISO Prolog.