The PrologJ Debugging Facilities

Overview

The PrologJ interpreter's debugging facilities are based on facilities discussed in [ Clocksin and Mellish 1994 ], but incorporate significant extensions beyond what is discussed there. For efficiency's sake, the "hooks" used by these mechanisms are not present in compiled code; however, these facilities can be used on interpreted code that is called by compiled code (e.g. by call/1 applied to a variable that is not instantiated until run time), or, to a limited extent, when compiled code is called from interpreted code. The intention, however, is that the interpreter will be used for code development, with compilation being done for efficiency after errors are found and removed.

To use any of the facilities described here, it is necessary that the built-in predicates belonging to the "Debugger" be loaded. This is the default, unless the predicates to load are explicitly specified via a command line option or the "Library Components" menu, as discussed in conjunction with the page about built-in predicates. Morerover, all of the facilities described here are dependent on the setting of the debug flag. When this flag is on, and the Debugger predicate category is loaded, the facilities described below are available. When this flag is turned off, the facilities described below are temporarily disabled. However, various status information (set by the means described below under "Enabling/Disabling Tracing") remains recorded, and the operations specified by those settings resume as soon as the flag is turned back on.

PrologJ's debugging facilities are based on the traditional "four event" model of Prolog goal execution:
 
Diagram showing traditional four event model

However, for user-defined predicates written in Prolog, PrologJ adds a fifth event which allows stepping through the clauses used to satisfy a goal (and their subgoals, if desired). This event occurs for each clause that can be used to satisfy the original goal, and for each of a clause's subgoals, if its body consists of multiple subgoals connected by ','/2.
 
Diagram showing PrologJ five event model

A given goal is said to be traced if debugging applies to that goal. When one of the four traditional events occurs for a traced goal, a message is displayed on standard output. This is true for any kind of predicate, not just for predicates written in Prolog.

The message has one of the forms shown below.

[invocation number] CALL goal
[invocation number] EXIT goal
[invocation number] FAIL goal
[invocation number] REDO goal

Where

For predicates written in Prolog, it is also possible to trace STEP events by explicitly requesting stepping. This is discussed below. (STEP events are not ordinarily traced because this would result in voluminous output.)

Leashed and Unleashed Tracing

Two different kinds of tracing are supported: leashed tracing, and unleashed tracing. The distinction is made on an event by event basis. If leashed tracing is enabled for a given event, then after the message about the event is printed, a "?" prompt is printed and the system waits for the user to issue one or more commands before proceeding. If the event is not leashed, execution proceeds normally after displaying the message, without waiting for a user-entered command. Note that leashed tracing is possible for any goal, regardless of what kind of predicate it calls.

In the discussion below, sometimes a goal will be referred to as a "leashed goal". A goal is leashed if one or more of its events are leashed. Any unleashed event of a leashed goal is always traced.

Commands Recognized During Leashed Tracing

The following commands are recognized when the user is prompted for a command at a leashed event. Commands may be abbreviated to any substring - even to their first letter. Debugger commands are not case sensitive. Not all commands are available at every event, however, as noted in the list below.

If the user simply presses "enter" or "return" without typing a command at any event, execution proceeds normally as it would if the event were not leashed. That is, "enter" or "return" without a command is equivalent to the command noted as the default for the particular event.

Some commands cause execution to proceed to the next event. Others are executed and then await a further command at the same event.

Command Meaning Events
The following cause execution to proceed to the next event
call Call the goal. If this command is issued at any event except the CALL event, it causes execution of the goal to start over from the very beginning, as if at the initial call. All variable bindings are undone, but side-effects from the previous call (e.g. output, modifications to the database) remain. All
Default at CALL
exit Declare the goal to have completed successfully. If this command is issued at any event except the EXIT event, it causes the goal to be treated as if it succeeded non-redoably, but without any variable unifications being done. (If this command is given at the EXIT event, the goal's redoability and variable bindings are not affected.) This command should be used with caution, since it forces the goal to succeed without doing any instantiations, which can lead to problems if subsequent predicates depend on instantiations done by this predicate All
Default at EXIT
fail Declare the goal to have failed. All
Default at FAIL
redo Attempt to find another way to satisfy the goal. The solution represented by the unifications presented is rejected. When this command is issued at the EXIT event, the effect is the same as if a subsequent goal had failed, forcing backtracking to redo this goal. At the REDO event, this command causes execution to proceed normally. Only EXIT and REDO
Default at REDO
step (Only applicable to goals which call a predicate that is written in Prolog.)
Attempt to proceed to the STEP event at the start of the first applicable clause (if given at the CALL event) or the STEP event at the end of the last clause that succeeded (if given at the REDO event).
If given at the CALL event of a goal for which there are no applicable clauses, execution will proceed to the FAIL event for the goal. If given at the REDO event for a clause that has no redoable subgoals, execution will proceed to either the STEP event of the next applicable clause, or to the FAIL event for the the goal.
When this command is given at the CALL or REDO event of a goal, it enables leashed tracing of the goal's STEP events, which would otherwise not be traced. This remains in effect for the goal until a EXIT or FAIL event is reached, unless cancelled earlier by user command at a STEP event. This is done on a goal by goal basis; there is no effect on the tracing of other goals which use the same predicate.
Only interpreted clauses can be stepped through. If an attempt is made to step through a compiled clause, execution will either proceed to the EXIT or FAIL event of the goal, or to the STEP event of an applicable interpreted clause for the same predicate (only if the current compiled clause does not satisfy the goal).
Only CALL or REDO, and only for goals which call a predicate written in Prolog
into (Only applicable to goals which call a built-in predicate which has subgoal(s) (e.g. bagof/3).) Continue execution of the goal, but with leashed tracing in effect for its subgoal(s). The same events are leashed for the subgoal as are leashed for the current goal; other events are simply traced. Only CALL and REDO. In the latter case, only applies to new goals that may be called when this predicate is being redone; leashed tracing of the redoing of subgoals called previously depends on whether into was used when they were called
unify The user is prompted to enter a term, which is then unified with the goal. If the unification succeeds, the result is the same as if the user had issued the exit command (with the unification remaining in effect); if the unification fails, the result is the same as if the user had entered the fail command. All
abort Abort execution of the goal, returning to the nearest top-level interpreter. (If issued for interpreted code called from compiled code, this may result in terminating the program.) All
The following accept another command at the current event after executing the command
writeq Write out the current goal using writeq/1. All
display Write out the current goal using display/1. All
vars Report the bindings of the variables that appeared in the top-level goal that initiated the computation leading to this point. All
break Enter a break loop, as if by break/0. When the break loop is terminated (by entering end-of-file), execution of the event at which the command was entered resumes. All
trace Turn on global (unleashed) tracing. If tracing is enabled specifically for any predicate, it remains enabled. All
notrace Turn off global (unleashed) tracing. If tracing is enabled specifically for any predicate, it remains enabled. All
history Print a history of goals called starting at the current goal and working back to top-level. All
? Display a brief help text on currently-available commands. All

Stepping through Clauses

When leashed tracing is enabled for a goal that calls a predicate written in Prolog, it is possible to step through the execution of its clauses by issuing the step command at its CALL event. In this case, a message like the following is printed just before the execution or redoing of each subgoal:

[invocation number] STEP [(new clause)] for clause clause-number for predicate 
head :-
	body
	...

Where

  • The phrase (new clause) is printed only at the first STEP for a given clause.
     
  • clause-number is the relative number of the clause among the clauses for its predicate (1 origin). Note that clauses whose head does not unify with the goal are skipped over.
     
  • head is the head of the clause, which has already successfully unified with the goal.
     
  • body is the body of the clause, which will consist either of a single subgoal (possibly true if the clause is a fact), or a series of subgoals, joined by ','/2, and each printed on a separate line.
     
    An execution marker (=>) will be printed just before the next subgoal to be executed (when stepping through the execution of the clause) or a redo marker (=> redo previous) just after the subgoal to be redone (when backtracking through a clause, either as the result of a redo or the failure of some subgoal). All variables appearing in the clause will reflect bindings resulting from unification of the head with the original goal plus any subgoals which have been successfully executed, including the subgoal to be redone during backtracking. (Initially, for execution of a clause, the marker will be just before the first subgoal in the body, and only variable bindings resulting from unification of the head with the original goal will have been done. For redoing a clause, the initial redo marker will be just after the last subgoal of the clause, and variable bindings will be as they were when the clause last succeeded.)
     
    A new STEP event will normally occur after the success or failure of each subgoal, with the marker moved down or up as the case may be. During backtracking, the redo marker may be moved back two or more subgoals if it can be determined for certain that a given subgoal is not redoable (e.g. it involved the execution of a non-redoable predicate).
     
    However, if the last subgoal succeeds, the EXIT event of the original goal will be traced instead of another STEP event; if the first subgoal fails, either the STEP event of the next applicable clause or the FAIL event of the original clause will be traced, instead of another STEP event for the current clause.

When stepping through the clauses of a predicate written in Prolog, the user is always asked to enter a command for each subgoal. The commands that are available are similar to, but not identical to, the commands available at the other four events. Simply pressing "return" or "enter" without a command is equivalent to step.

Command Meaning
The following cause execution to proceed to the next event
callSame as for the other four events - see description of regular debugger commands above
overStart the current clause over from the initial unification of the head with the goal. Note that this differs from call in that only the current clause is started over - not the entire goal.
exitCause the current clause to succeed without doing any further steps, causing execution to proceed at once to the EXIT event of the goal. Variable instantiations resulting from unification with the head or previously satisfied subgoals remain in force. Should the goal subsequently be redone, any subgoals completed prior to the place where this command was issued can be redone, and any subsequent applicable clauses for the same predicate can be tried.
Note that the exit command issued at a STEP event differs from the same command issued at some other event, in that the success of the goal is potentially redoable, and some variable instantiations may have been done.
failSame as for the other four events - see description of regular debugger commands above
quitAbandon attempts to use the current clause to satisfy/resatisfy the goal. Execution will proceed to the first STEP event of the next applicable clause, if there is one, or to the FAIL event of the goal. Note that this differs from fail in that only the current clause is abandoned - not the entire goal.
(redo not available)
step Attempt to advance to the STEP event for the next subgoal, by executing or redoing the current subgoal.
If the subgoal is the last for its clause, and succeeds, execution will proceed to the EXIT event for the goal.
If the subgoal fails, execution may fall back to a previous redoable step in the current clause, or to the STEP event at the start of a new clause, or to the FAIL event for the goal, as the case may be.
into Continue execution as if by the step command, but with leashed tracing in effect for the subgoal to be called/redone. The same events are leashed for the subgoal as are leashed for the current goal; other events are simply traced. In the case where a subgoal is to be redone, this command is only allowed if the subgoal was originally called using into.
leap Proceed through the execution/redoing of the current goal without further tracing of STEP events - as if the step command had not been issued. The next event reached will either be the EXIT or FAIL event for the goal. Note that the cancellation of stepping applies not only to the current clause, but also to any subsequent clauses that may be attempted to satisfy/resatisfy the goal. (If the goal is satisfied/resatisfied and then redone, it is possible to initiate stepping again by using the step command at the REDO entry.)
jump Proceed through the execution/redoing of the current clause without further tracing of STEP events. If the clause succeeds, the next event reached will be the EXIT event for the goal. If it fails, the next event reached will either be the STEP event for the next applicable clause, or the FAIL event for the goal. Note that this applies only to the current clause; if a new clause is attempted, it will be stepped through
unifySame as for the other four events - see description of regular debugger commands above
abortSame as for the other four events - see description of regular debugger commands above
The following accept another command at the current event after executing the command
writeqSame as for the other four events - see description of regular debugger commands above
displaySame as for the other four events - see description of regular debugger commands above
varsSame as for the other four events - see description of regular debugger commands above
breakSame as for the other four events - see description of regular debugger commands above
traceSame as for the other four events - see description of regular debugger commands above
notraceSame as for the other four events - see description of regular debugger commands above
historySame as for the other four events - see description of regular debugger commands above
?Same as for the other four events - see description of regular debugger commands above

It is only possible to step through interpreted clauses. If a compiled clause is used to satisfy the goal, it is executed to completion immediately, and execution proceeds either to the next clause or to the EXIT or FAIL event of the goal.

Enabling and Disabling Tracing

Goals can become traced in one of three ways:

  • By turning on tracing on a global basis for all goals. (Note 1)
  • By explicitly turning on tracing for a given predicate, which causes any goal that uses that predicate to be traced. (Notes 1, 2)
  • By stepping into the subgoals of a leashed goal or clause, which causes the subgoal(s) to be leashed as well. (Notes 1, 2)

Notes:

  1. The predicate ','/2 can never be traced, and it is an error to attempt to turn on tracing for it. During exhaustive tracing, it is ignored. If into is used to leash a subgoal which uses this predicate (which will only happen if parentheses are used to override the normal parsing of operators or it appears as the instantiation of a variable that is called as by call/1), then its subgoals will be leashed instead.
     
  2. Certain predicates that serve as control structures cannot be leashed, and it is an error to attempt to turn on leashed tracing for one of them - though unleashed tracing is allowed. If into is used to leash a subgoal which uses one of these predicates, it will be traced (but not leashed), and its subgoal(s) will be leashed instead.
     
    • call/1
    • call_fuzzy/1
    • catch/3
    • ','/2
    • ';'/2
    • foreach/2
    • ->/2
    • -> ;
    • not/1
    • +/1
    • once/1

PrologJ keeps track of tracing information for individual predicates separately from global tracing information and goal tracing information. Thus, for example, if tracing is turned on for a given predicate and then is also turned on globally, and global tracing is subsequently turned off, tracing will remain on for the specific predicate.

Only unleashed tracing can be turned on globally. Either leashed or unleashed tracing can by turned on for a specific predicate. When a subgoal of a leashed goal is called as a result of the into command, it is also leashed in then same way. If both leashed and unleashed tracing apply to a given goal (due to using some combination of the above), the goal is leashed. When specific events of a goal are leashed, the remaining events are always traced.

Builtin Predicates for Controlling Tracing

The following built-in predicates can be used to enable/disable tracing or to inquire about the current state of tracing.

Copyright © 2005 - Russell C. Bjork. See the file See file COPYING in the root directory for copyright information.

Valid XHTML 1.0!