Error handling is one particular use of events.
The main property of error events is that they have a culprit goal,
ie. the goal that detected or caused the error.
The error handler obtains that goal as an argument.
The errors that the system raises have numerical identifiers,
as documented in appendix C.
User-defined errors have atomic names, they are the same as events.
Whenever an error occurs, the ECLiPSe system identifies the type of error, and
calls the appropriate handler. For each type of error, it is possible
for the user to define a separate handler. This definition will replace
the default error handling routine for that particular error - all other
errors will still
be handled by their respective
It is of
course possible to associate the same user defined error handler to more
than one error type.
When a goal is called and produces an error, execution of the goal
is aborted and the appropriate error handler is invoked.
This invocation of the error handler is seen as replacing
the invocation of the erroneous goal:
For errors that are classified as warnings the second point is somewhat
different: If the handler succeeds, the goal that raised the warning
is allowed to continue execution.
If the error handler fails it has the same effect as if the
erroneous goal failed.
- If the error handler succeeds, possibly binding some variables,
the execution continues at the point behind the call of the erroneous goal.
- If the handler calls exit_block/1, it has the same effect as if
this was done by the erroneous goal itself.
Apart from binding variables in the erroneous goal, error handlers can
also leave backtrack points. However, if the error was raised by
an external or a builtin that is implemented as an external, these
choicepoints are discarded3.
13.2.1 Error Handlers
The predicate set_event_handler/2 is used to assign a procedure as
an error handler. The call
sets the event handler for error type ErrorId to the procedure specified by
PredSpec, which must be of the form Name/Arity.
The corresponding predicate get_event_handler/3 may be used to identify
the current handler for a particular error. The call
will, provided ErrorId is a valid error identifier, unify PredSpec
specification of the current handler for error ErrorId in the form
Name/Arity, and HomeModule will be unified with the module where the
error handler has been defined. Note that this error handler might not be
visible from every module and therefore may not be callable.
get_event_handler(ErrorId, PredSpec, HomeModule)
To re-install the system's error handler in case the user error handler is
no longer needed, reset_event_handler/1 should be used.
reset_error_handlers/0 resets all error handlers to their default values.
To enable the user to conveniently write predicates with error checking
are provided to raise the error ErrorId (an error number or a name atom)
with the culprit Goal.
Inside tool procedures it is usually necessary to use error/3
in order to pass the caller module to the error handler.
Typical error checking code looks like this
error(ErrorId, Goal, Module)
The predicate current_error/1
can be used to yield all valid error numbers, a valid error is that one
to which an error message and an error handler are associated.
The predicate error_id/2
gives the corresponding error message to the specified error number.
To ease the search for the appropriate error number,
the library util contains the predicate
increment(X, X1) :-
( integer(X) ->
X1 is X + 1
error(5, increment(X, X1))
which returns on backtracking all the errors whose error message
contains the string Text.
util:list_error(Text, N, Message)
The ability to define any Prolog predicate as the error handler permits a
great deal of flexibility in error handling. However, this flexibility
should be used with caution. The action of an error handler could have side
effects altering the correctness of a program; indeed it could be responsible
for further errors being introduced. One particular area of danger is in the
use of input and output streams by error handlers.
13.2.2 Arguments of Error Handlers
An error handler has 4 optional arguments.
The error handler is free to ignore some of these arguments,
i.e. it can have any arity from 0 to 4.
The first argument is provided for the case that the same procedure serves
as the handler for several error types - then it can distinguish
which is the actual error type.
An error handler is just an ordinary Prolog procedure and thus within
it a call may be made to any other procedure, or any built in predicate;
this in particular means that a call to exit_block/1 may be
made (see the section on the block/3
predicate). This will work
'through' the call to the error handler, and so an exit may be made from
within the handler out of the current block (i.e. back to the corresponding
call of the block/3 predicate).
Specifying the predicates true/0 or fail/0 as error handlers
will make the erroneous predicate succeed (without binding
any further variables) or fail respectively.
The first argument is the number or atom that identifies the error.
- The second argument is
the culprit (a structure corresponding to the call which caused the
For instance, if,
say, a type error occurs upon calling the second goal of the procedure
the structure given to the error handler is b(2, Y).
Note that the handler could bind Y which would have the same effect
as if b/2 had done the binding.
p(X, Y) :- a(X), b(X, Y), c(Y).
- The third argument is only defined for a subset of the existing errors.
If the error occurred inside a tool body, it holds the caller module,
otherwise it is identical to the fourth argument4.
- The fourth argument is the lookup module for the culprit goal. This
is needed for example when the handler wants to call the culprit reliably,
using a qualified call via : /2.
The following two templates are the most common for error handlers.
The first simply prints an error message and aborts:
my_error_handler(ErrorId, Goal, ContextModule) :-
printf(error, "Error %w in %w in module %w%n",
The following handler tries to repair the error and call the goal again:
my_error_repair_handler(ErrorId, Goal, ContextModule, LookupModule) :-
% repair the error
... some code to repair the cause for the error ...
% try call the erroneous goal again
LookupModule : Goal @ ContextModule.
13.2.3 User Defined Errors
The following example illustrates the use of a user-defined error.
We declare a handler for the event 'Invalid command' and
raise the new error in the application code.
% Command error handler - output invalid command, sound bell and abort
command_error_handler(_, Command) :-
printf("\007\nInvalid command: %w\n", [Command]),
% Activate the handler
:- set_event_handler('Invalid command', command_error_handler/2).
% top command processing loop
error('Invalid command',Command) % Call the error handler
% Some valid commands