It's possible for ancestors to disagree about Restart (aka, different values on backtracking). In this scenario, it's acceptable to choose the first (innermost) Restart, iterate each Restart in turn or consider all Restart values together (quorum?).
If no ancestor has an opinion, signal/2 calls throw(Condition)
.
If you'd rather use a default value for Restart in this case,
use signal/3 instead.
It's quite common for signal/2 to leave dangling, false
choicepoints. If you're only interested in the first Restart value,
use once/1 or a similar construct to explicitly state that intent.
var(Restart)
to see if a restart was provided.
For example,
signal(oops, Restart, Restart), ( var(Restart) -> print_message(warning,"Nobody provided a restart") ; ... )
% if stuff signals oops(_) then restart with carry_on handle(stuff, oops(_), carry_on)
call(Restarter, Condition, Restart)
to
determine which Restart value should be sent to the signaler.
Restarter may fail which allows other handlers higher up the call
stack to address this condition. Restarter may produce multiple
Restart values on backtracking, if multiple restarts are plausible.
When using handle/2, consult the documentation of those predicates that might signal conditions. They'll explain which Restart values are acceptable, what they do and whether generating Restart values on backtracking makes sense.
If more than one handle/2 is in effect within the current call stack, Restarter values are executed from the innermost to the outermost ancestor. This allows those "closest" to the signal a chance to handle it before it propagates outward. Of course, if a signaler looks at multiple solutions, other handlers will be executed too.
add_handler(restarter, Ref), foo(a), % signals handled by restarter/2 foo(b), % ditto rm_handler(Ref).
Of course, to be safe, one should use the built in setup_call_cleanup/3 or cleanup/1 provided by library(sweet). That makes sure the handler is removed no matter how foo/1 misbehaves.