In all the examples so far a breakpoint was put on a specific
predicate, described by a goal
or pred
test. Such
breakpoints are called specific, as opposed to generic
ones.
Generic breakpoints are the ones that do not specify a concrete
predicate. This can happen when the breakpoint spec does not
contain goal
or pred
tests at all, or their argument
is not sufficiently instantiated. Here are some examples of
generic breakpoints:
| ?- add_breakpoint(line('/home/bob/myprog.pl',6), _). % Generic spypoint added, BID=1 | ?- add_breakpoint(pred(foo/_), _). % Generic spypoint added, BID=2 | ?- add_breakpoint([goal(G),true((arg(1,G,X),X==bar))], _). % Generic spypoint added, BID=3
The first breakpoint will stop at all calls in line 6 of the given
file, the second at all calls of a predicate foo
,
irrespective of the number of arguments, while the third one will
stop at any predicate with bar
as its first
argument. However, there is an additional implicit condition: the
module name expansion inserts the type-in module as the
default module name in the goal
and pred
conditions. Consequently, the second and third breakpoint applies
only to predicates in the type-in module (user
by
default). If you would like the breakpoint to cover all
modules you have to include an anonymous module prefix
in the argument of the goal
or pred
test:
| ?- add_breakpoint(pred(_:foo/_), _). % Generic spypoint added, BID=1 % zip | ?- add_breakpoint([goal(_:G),true((arg(1,G,X),X==bar))], _). % Generic spypoint added, BID=2
Generic breakpoints are very powerful, but there is a price to pay: the zip mode is slowed down considerably.
As said earlier, in principle the debugger is entered at each port of each procedure invocation. As an optimization, the debugger can request the underlying Prolog engine to run at full speed and invoke the debugger only when one of the specified predicates is called. This optimization is used in zip mode, provided there are no generic breakpoints. In the presence of generic breakpoints, however, the debugger has to be entered at each call, to check their applicability. Consequently, with generic breakpoints, zip mode execution will not give much speed-up over debug mode, although its space requirements will still be much lower.
It is therefore advisable to give preference to specific
breakpoints over generic ones, whenever possible. For example, if
your program includes predicates foo/2
and
foo/3
, it is much better to create two specific
breakpoints, rather than a single generic one with conditions
[pred(foo/_),...]
.
spy/2
is a built-in predicate that will create
specific breakpoints only. Its first argument is a
generalized predicate spec, much like in spy/1
, and the
second argument is a breakpoint spec. spy/2
will
expand the first argument to one or more predicate specs,
and for each of these will create a breakpoint, with a pred
condition added to the test part of the supplied breakpoint
spec. For example, in the presence of predicates foo/2
and
foo/3
| ?- spy(foo/_, file(...))
is equivalent to:
| ?- add_breakpoint([pred(foo/2),file(...)], _), add_breakpoint([pred(foo/3),file(...)], _).
Note that with spy/[1,2]
it is not possible to put a
breakpoint on a (yet) undefined predicate. On the other
hand, add_breakpoint/2
is perfectly capable of creating such
breakpoints.