This simulates an occurrence of the error EventId inside a call to Culprit. The valid error numbers are those returned by current_error/1. Event names can be any atom as long as an event handler has been defined for them.
If EventId is a structure with functor default/1, the structure's argument is taken as the error number and the default handler is executed, even if the error handler has been redefined using set_event_handler/2. This is useful for writing user error handlers.
If the event handler succeeds, possibly binding some variables inside Culprit, then error/2 succeeds as well. If the handler fails or calls throw/1, then so does error/2.
Success:
   % Writing a predicate with type checking
    ?- [user].
     is_positive(N) :-
            number(N),
            !,
            N >= 0.
     is_positive(N) :-
            error(5, is_positive(N)).
     user compiled 244 bytes in 0.02 seconds
    yes.
    ?- is_positive(a).
    type error in is_positive(a)
   % changing the behaviour of a built-in by redefining a handler
    ?- //(1,0,X).       % change this behaviour
    arithmetic exception in //(1, 0, X)
    ?- [user].        % define the new handler
     my_handler(_, //(_,_,Result)) :-
            !,
            Result = infinity.
     my_handler(Err, Goal) :-
            error(default(Err), Goal).
     user compiled 212 bytes in 0.00 seconds
    yes.
    ?- set_event_handler(20, my_handler/2).
    yes.
    ?- //(1,0,X).      % check if it works
    X = infinity
    yes.
    ?- sqrt(-1,X).   % other culprits: as before
    arithmetic exception in sqrt(-1, _g36)
Error:
      error(N,dummy(1)).    (Error 4).
      error(5.0,dummy(1)).  (Error 5).
      error(-2,dummy(1)).   (Error 6).