Sometimes even spy points aren't enough. There may be a predicate that is used in many different places and it would be helpful to turn on tracing mode only when one particular call to it is made. Breakpoints allow for turning on trace mode when a specific source file, line number, and character in that line are hit. The predicates used are set_breakpoint/4 and set_breakpoint/5. Many breakpoints can be active at a time.
Note that the interface provided by these predicates is not intended for end-users. The built-in PceEmacs editor that is also embedded in the graphical debugger allow setting break points based on the cursor position.
Example.pl
has now been modified to have multiple calls
to noun/2 :
is_a(rock1, rock). is_a(rock2, rock). color(rock1, red). noun(X, Type) :- is_a(X, Type). adjective(X, color, Value) :- color(X, Value). test_noun1(X, Type) :- noun(X, Type). test_noun2(X, Type) :- noun(X, Type).
To enable tracing just when noun/2 is called from test_noun2/2 , set_breakpoint/4 can be used like this:
?- set_breakpoint('/...path.../Example.pl', 8, 24, ID). % Breakpoint 1 in 1-st clause of test_noun2/2 at Example.pl:8 ID = 1. ?- debug. true. [debug] ?- noun(X, rock). X = rock1 . [debug] ?- test_noun1(X, rock). X = rock1 . [debug] ?- test_noun2(X, rock). Call: (11) noun(_44982, rock) ? creep Call: (12) is_a(_44982, rock) ? creep Exit: (12) is_a(rock1, rock) ? creep Exit: (11) noun(rock1, rock) ? creep Exit: (10) test_noun2(rock1, rock) ? creep X = rock1 . [trace] ?- notrace. true. [debug] ?-
The call to set_breakpoint/4 had to
specify the source file ("Example.pl
"), the line number
(8), and the character within that line (24) to precisely specify what
clause should turn on trace mode (this is much easier using the
graphical debugger because it shows source code).
The breakpoint won't get triggered if the system isn't in debug mode but, unlike setting a spy point, set_breakpoint/4 does not do this automatically. So, it was turned on manually using debug/0.
The output shows that only the call to test_noun2/2 (where the
breakpoint was set) actually turned on trace mode. Note that the
[Trace] ?-
at the end shows that trace mode is left on
after being triggered. It can be turned off again via notrace/0,
which will leave the system in debug mode. All debugging modes can be
shut off at once by calling nodebug/0
since shutting off debug mode automatically turns off trace mode.
In addition, SWI-Prolog supports attaching an arbitrary goal to each breakpoint via set_breakpoint_condition/2, which yields Conditional Breakpoints. A conditional breakpoint is the same as the regular breakpoints discussed thus far, except that whenever the breakpoint is triggered, the given goal is invoked and trace mode is only turned on in case it succeeds.
To enable tracing just when noun/2 is called from test_noun2/2 with rock2
as the first argument, set_breakpoint_condition/2
can be used like below. Note that the condition is a Prolog string that
is parsed to obtain the goal as well as the variable names. The
resulting goal is called in the module in which the clause body is
executed (see
clause_property/2,
property module
).
?- set_breakpoint('/...path.../Example.pl', 8, 24, ID). ID = 1. ?- set_breakpoint_condition(1, "X == rock2"). true. ?- debug. true. [debug] ?- test_noun2(X, rock). X = rock1 ; X = rock2. [debug] ?- test_noun2(rock2, rock). Call: (11) noun(rock2, rock) ? creep Call: (12) is_a(rock2, rock) ? creep Exit: (12) is_a(rock2, rock) ? creep Exit: (11) noun(rock2, rock) ? creep Exit: (10) test_noun2(rock2, rock) ? creep true. [trace] ?-