The action part of a breakpoint specification supplies information to the debugger as to what should be done when the breakpoint is activated. This is achieved by setting the three so called debugger action variables. These are listed below, together with their most important values.
showvariable prescribes how the debugged goal should be displayed:
write the goal according to
debugger_print_options Prolog flag.
do not display the goal.
commandvariable prescribes what the debugger should do:
ask the user.
continue the execution without stopping, creating a procedure box for the current goal at the Call port,
continue the execution without stopping, without creating a procedure box for the current goal at the Call port.
modevariable prescribes in what mode the debugger should continue the execution:
For example, the breakpoint below specifies that whenever the Exit
foo/2 is reached, no trace message should be
output, no interaction should take place and the debugger should be
| ?- add_breakpoint([pred(foo/2),port(exit)]- [show(silent),command(proceed),mode(off)], _).
Here, the action part consists of three actions, setting the three
action variables. This breakpoint specification can be simplified by
omitting the wrappers around the variable values, as the sets of
possible values of the variables are all disjoint. If we use
spy/2, then the
pred wrapper goes away, too, resulting in a
much more concise, equivalent formulation of the above breakpoint:
| ?- spy(foo/2,exit-[silent,proceed,off]).
Let us now revisit the process of breakpoint selection. When the debugger arrives at a port it first initializes the action variables according to the current debugging and leashing modes, as shown below:
debugging leashing | Action variables mode mode | show command mode --------------------------------|------------------------------- trace at leashed port | print ask trace | trace at unleashed port | print proceed trace | debug - | silent proceed debug | zip - | silent flit zip
It then considers each breakpoint, most recent first, until it
finds a breakpoint whose test part succeeds. If such a
breakpoint is found, then its action part is evaluated, normally
changing the action variable settings. A failure of the action part is
ignored, in the sense that the breakpoint is still treated as the
selected one. However, as a side effect, a procedure box
will always be built in such cases. More precisely, the failure of the
action part causes the
flit command value to be changed to
proceed, all other command values being left unchanged. This is
to facilitate the creation of breakpoints that stop at non-Call
ports (see below for an example).
If no applicable breakpoint is found, then the action variables remain unchanged.
The debugger then executes the actions specified by the action variables. This process, referred to as the action execution, means the following:
ask, then the user is prompted
for a debugger command, which in turn is converted to new assignments to
the action variables. The debugger will then repeat the action execution
process, described above. For example, the ‘c’ (creep) interactive
command is converted to
[silent,proceed,trace], the ‘d’
(display) command to
[display,ask] (when command is
the mode is irrelevant), etc.
The default values of the action variables correspond to the standard debugger behavior described in Basic Debug. For example, when an unleashed port is reached in trace mode, a trace message is printed and the execution proceeds in trace mode, without stopping. In zip mode, no trace message is shown, and execution continues in zip mode, without building procedure boxes at Call ports.
Note that a spypoint action part that is empty (
 or not
present) is actually treated as
[print,ask]. Again, this is the
standard behavior of spypoints, as described in Basic Debug.
If an action part is nonempty, but it does not set the action variables, then the only effect it will have is to hide the remaining older spypoints, as the debugger will behave in the standard way, according to the debugging mode. Still, such breakpoints may be useful if they have side effects, for example:
| ?- spy(foo/2, -[parent_pred(P), goal(G), true(format('~q called from:~w~n',[G,P]))]). % The debugger will first zip -- showing spypoints (zip) % Conditional spypoint for user:foo/2 added, BID=1 true % zip | ?- foo(3,X). foo(2,_701) called from:bar/3 foo(1,_1108) called from:bar/3 foo(0,_1109) called from:bar/3 foo(1,_702) called from:bar/3 X = 2 ? ; no
This spypoint produces some output at ports of
but otherwise will not influence the debugger. Notice that a
breakpoint specification with an empty test part can be written
Let us look at some simple examples of what other effects can be achieved by appropriate action variable settings:
| ?- spy(foo/2, -[print,proceed]).
This is an example of an unleashed spypoint: it will print a
trace message passing each port of
foo/2, but will not stop
there. Note that because of the
proceed command a procedure
box will be built, even in zip mode, and so the debugger will be
activated at non-Call ports of
The next example is a variant of the above:
| ?- spy(foo/2, -[print,flit]).
This will print a trace message at the Call port of
and will then continue the execution in the current debugging mode,
without building a procedure box for this call. This means that
the debugger will not be able to notice any other ports of
Now let us address the task of stopping at a specific non-Call
port of a predicate. For this to work in zip mode, one
has to ensure that a procedure box is built at the Call
port. In the following example, the first spypoint causes a
box to be built for each call of
foo/2, while the second one
makes the debugger stop when the Fail port of
| ?- spy(foo/2, call-proceed), spy(foo/2, fail). % Conditional spypoint for user:foo/2 added, BID=1 % Conditional spypoint for user:foo/2 added, BID=2
You can achieve the same effect with a single spypoint, by putting
fail condition (which is a shortcut for
the action part, rather than in the test part.
| ?- spy(foo/2, -[fail,print,ask]).
Here, when the execution reaches the Call port of
the test part (which contains the
pred(foo/2) condition only)
succeeds, so the breakpoint is found applicable. However, the
action part fails at the Call port. This has a side effect
in zip mode, as the default
flit command value is changed
proceed. In other modes the action variables are
unaffected. The net result is that a procedure box is always built
foo/2, which means that the debugger will actually reach the
Fail port of this predicate. When this happens, the action
part succeeds, and executing the actions
print,ask will cause the
debugger to stop.
Note that we have to explicitly mention the
here, because the action part is otherwise nonempty (contains the
fail condition). It is only the empty or missing action part,
which is replaced by the default
[print,ask]. If you want to
include a condition in the action part, then you have to explicitly mention
all action variable settings you need.
To make this simpler, the debugger handles breakpoint condition
macros, which expand to other conditions. For example
leash is a
macro that expands to
[print,ask]. Consequently, the last example
can be simplified to:
| ?- spy(foo/2, -[fail,leash]).
Similarly, the macro
unleash expands to
We now briefly describe further possible settings to the action variables.
mode variable can be assigned the values
qskip(Inv), meaning skipping and
quasi-skipping until a port is reached whose invocation number is
less or equal to Inv. When the debugger arrives at this port
it sets the
mode variable to
It may be surprising that
skip(…) is a mode, rather than a
command. This is because commands are executed and immediately
forgotten, but skipping has a lasting effect: the program is to be
run with no debugging until a specific point, without creating new
procedure boxes, and ignoring the existing ones in the meantime.
Here is an example using the
| ?- spy(foo/2,call-[print,proceed,inv(Inv),skip(Inv)]).
This breakpoint will be found applicable at Call ports of
foo/2. It will print a trace message there and will skip over to
the Exit or Fail port without stopping. Notice that the number of
the current invocation is obtained in the action part, using the
inv condition with a variable argument. A variant of
this example follows:
| ?- spy(foo/2,-[silent,proceed, ( call -> inv(Inv), skip(Inv) ; true )]).
This spypoint makes
foo/2 invisible in the output of the
debugger: at all ports we silently proceed (i.e. display nothing
and do not stop). Furthermore, at the Call port we perform a
skip, so neither
foo/2 itself, nor any predicate called
within it will be shown by the debugger.
Notice the use of the
true/0 test in the above conditional! This
is a breakpoint test that always succeeds. The debugger also
false as a test that always fails. Note that while
fail are synonyms as built-in predicates,
they are completely different as breakpoint conditions: the latter
is a shortcut for
show variable has four additional value patterns. Setting it
will result in the debugged goal G being shown using
write_term(G, Options), respectively. The fourth
Method-Sel, can be used for replacing the
goal in the trace message by one of its subterms, the one
pointed to by the selector Sel.
For example, the following spypoint instructs the debugger to stop
at each port of
foo/2, and to only display the first
foo/2 in the trace message, instead of the
| ?- spy(foo/2, -[print-,ask]). % Conditional spypoint for user:foo/2 added, BID=1 | ?- foo(5,X). * 1 1 Call: ^1 5 ?
command variable has several further value patterns. The
variable can be set to
proceed(OldGoal,NewGoal). At a
Call port this instructs the debugger to first build a
procedure box for the current goal, then to unify it
with OldGoal and finally execute NewGoal in its place (cf.
the ‘u’ (unify) interactive debugger command). At non-Call
ports this command first goes back to the Call port (cf.
the ‘r’ (retry) command), and then does the above activities.
A variant of the
proceed/2 command is
flit(OldGoal,NewGoal). This has the same effect,
except for not building a procedure box for OldGoal.
We now just briefly list further command values (for the details, see
Action Variables). Setting
raise(E) will raise an exception E,
will abort the execution. The values
will cause the debugger to go back to an earlier Call, Exit, Redo, or
Fail port with invocation number Inv (cf. the ‘j’
(jump) interactive debugger command).
Sometimes it may be useful to access the value of an action
variable. This can be done with the
get condition: e.g.
get(mode(M)) will unify
M with the current execution
get(…) wrapper can be omitted in the test part,
but not in the action part (since there a
mode(M) action will
set, rather than read, the mode action variable). For example:
| ?- spy(foo/2, mode(trace)-show(print-)).
This spypoint will be found applicable only in trace mode
(and will cause the first argument of
foo/2 to appear in
the trace message). (The
show wrappers can also
be omitted in the above example, they are used only to help with interpreting
the breakpoint specification.)