You are on page 1of 21

N(IRTH- HOLLAND

A Visual Debugger for Pure Prolog

DAN E. TAMIR

RAVI ANANTHAKRISHNAN
Department of Computer Science, Florida Institute of Technology, 150 W. University
Bculeward., Melbourne Florida 32901

AI3RAHAM KANDEL
Department of domputer Science and Engineering, University of South Florida, 4202
Eost Fowler Avenue, Tampa Florida 33620

ABSTRACT

This work involves the design and coding of an interpreter for pure Prolog and
building a visual debugger for it. Most of the available Prolog interpreters contain
some tracing facilities. They do not incorporate, however, a comprehensive visual
debugger. The interpreter performs the operations of parsing, unification, res-
olution, and search in a state-space representation of the Prolog program. The
visual debugger incorporates the graphical visualization and the manipulation
of the SLD resolution tree. The user visualizes the execution of a pure Prolog
program and interacts with the program inside a windowing environment. The
program execution may be viewed without interruption or the execution can be
stopped at any moment in time. At this point the “snapshot” can be scrutinized
w-ith the help of break-points and data displays. This software aims itself to those
who wish to observe the actual process of predicate unification, substitution, reso
lution, and goal matching in a Prolog program and to visually interact with the
interpreter using a highly friendly and pleasing user interface. An advanced fea-
ture, referred to as debugging on the tree, provides the user with the ability to
insert break-points directly on the SLD tree, to choose the path of execution,
and change the search mode. The resultant search algorithm can be a mixture
of depth-first and breadth-first search, avoiding infinite search paths.

INFORMATION SCIENCES 3, 127-14’7 (1995)


@ Elsevier Science Inc., 1995 0020-0255/95/$9.50
6!55 Avenue of the Americas, New York, NY 10010 SSDI 0020-0255(94)00048-G
128 TAMIR ET AL.

1. INTRODUCTION

1.1. Motivation
Prolog is a declarative logic programming language with a fixed and
deterministic control structure. The program control is based on the pro-
cess of proof by refutation of first order logic. Along with Lisp, Prolog is
one of the two most commonly used artificial intelligence (AI) languages.
A variety of AI applications have been developed in Prolog. Hence, of
major concern for the AI community are the issues governing efficient in-
terpretation of Prolog programs, parallel execution of Prolog programs,
and construction of efficient Prolog development tools.
In an ideal declarative language, the programmer specifies the problem
to be solved rather than the algorithm for problem solution. This approach
has several advantages over other programming paradigms. First, from the
software engineering point of view, the process of program development
“terminates” in the stage of problem specifications. Second, it has the ad-
vantage of freeing the programmer from the details of execution control.
Finally, because the programmer is not concerned with execution control,
the actual implementation of the control unit can be optimized and paral-
lelized independently of the user programs.
Nevertheless, the lack of interaction between the programmer and the
program exeuction control can lead to a less efficient problem solution.
Furthermore, a programmer who is not aware of the details of the fixed
execution control might find it extremely difficult to locate logic errors
(“bugs”).
Prolog is not an ideal declarative language. Hence, some of the foregoing
problems are amplified. On one hand, some execution control clauses are
available in practical Prolog implementations, so the programmer is not
completely free from execution control considerations. On the other hand,
the built-in control of Prolog, the procedure of proof by refutation, is not
trivial or simple to explain. Hence, many Prolog textbooks present a naive
and distorted view of Prolog to new Prolog programmers. For these rea-
sons, the development of Prolog debugging tools that visualize the actual
execution model of Prolog is an important consideration.
This research concentrates on the problem of Prolog development tools.
The visual debugger for Prolog reported in this paper is part of our current
effort to develop an efficient visual debugger for a parallel Prolog inter-
preter.
A VISUAL DEBUGGER FOR PURE PROLOG 129

1 .L’. Program Debugging Tools


A debugger is a computer program that facilitates user-controlled exe-
cutsion of other programs. Generally, a debugger enables tracing the execu-
tion of a program, setting break-points, stepping through the program, and
testing intermediate values of variables. Intelligent use of a debugger can
result in a substantial reduction in software development time. Araki et
al. [l] present a general framework for debugging. They define debugging
as the process of developing hypotheses about program behavior and then
verifying or refuting them. Araki et al. lists debug statements, break-point
insertion, stepping, and tracing as the most important components of a
debugger.
The visualization of complex and dynamic systems is an effective means
of feedback to the system designers and users. It can enable detection and
correction of errors, improve system performance, and optimize system
procedures. The computing literature includes a vast number of examples
of process/system visualization techniques [3]. Visualization of computer
algorithms, data structures, and program execution is a specific area in
which visual tools can be used effectively to enhance the productivity of
software development and usage [7, 91.
A visual debugger gives the user an opportunity to interact with the
program graphically. The graphical display enhances the understanding of
the specific way in which the program proceeds.

1. (9. Prolog Debugging Tools


In contrast to other programming languages such as Pascal, C, Ada, and
Lisp, Prolog has a fixed execution model in which the interpreter constructs
a state-space tree, referred to as the SLD tree, and performs depth-first
search on the tree. As a result, the Prolog programmer has limited control
over the execution of a Prolog program.
Prolog debugging tools can be used to resolve some of the inherent prob-
lems in Prolog program development. First, because the SLD tree can be
infinite, the depth-first search algorithm employed by Prolog can lead to a
nonterminating branch even though a solution may exist in the SLD tree.
Practically, however, in such a case, the program terminates with failure
when it runs out of resources. In many cases, changing the order of clauses
ca.n change the order of node exploration in the depth-first search. This
can change the results of the execution. Hence, sometimes it is necessary
to reorder the Prolog clauses in order to obtain a solution [6]. This fact is
well known to professional Prolog programmers. New programmers, how-
ever, are less familiar with this problem. A Prolog debugger can assist the
programmer to identify this type of problems and to reorder the program
TAMIR ET AL.

clauses. Another set of logic errors is related to the fact that the “occur
check” that is an essential part of unification is not being implemented in
Prolog (the exact definitions of the search method and the occur check are
given in a later section). In this case the debugger can help the program-
mer to identify a run-time error that is due to the lack of the occur check.
The programmer can then resolve the problem through a simple renaming
of variables. Finally, most of the Prolog textbooks and training courses
present a naive and nonaccurate view of Prolog, trying to equate Prolog
with procedural languages. The result is that many Prolog programmers
have a distorted view of the Prolog execution model. A tool that enables
program execution in a manner that shows the various paths of control flow
and the intermediate values of the parameters involved in the program can
help the programmer to understand accurately the details of the program
execution.
The difference between Prolog and other programming languages im-
poses conceptual and practical difficulties on the development of Prolog
debugging tools. ‘I’he main purpose of a debugger is to enable controlled
execution of a program. However, if the language does not enable con-
trol over the program execution, then how can the debugger enable this
control? In other words, how can the programmer insert a break-point
in a declarative language with no control structures. As a result of this
difficulty, traditional Prolog debugging tools concentrate on tracing rather
than controlling the execution. Nevertheless, because the control struc-
ture is fixed and independent of the program, it is possible to visualize the
general execution model of Prolog. This feature is not straightforward in
other programming language where the execution model depends on the
program. The visual model of Prolog execution can be used to animate
the execution of specific programs. Moreover, with additional facilities it
can be used to enable controlled execution of the program. In this sense,
the visual debugger reported in this paper is unique. As with other visual
Prolog tracers, our debugger draws the SLD tree while the Prolog program
executes. However, in contrast to existing Prolog debugging tools, it en-
ables control over the program execution using features such as inserting
break-points into the SLD tree and selecting alternative execution models
interactively.
Generally, a Prolog interpreter incorporates special predicates for trac-
ing, which enable limited debugging1 of the execution of Prolog programs.
The most commonly used model for tracing has been developed by Byrd
[2]. This model tries to equate Prolog execution with procedural language

lBecause no mechanism for break-point insertion, stepping, and controlled execution


is available, the debugging capability of these predicates is limited.
A VISUAL DEBUGGER FOR PURE PROLOG 131

execution. A set of clauses for a given predicate is viewed as a procedure


represented graphically by a box. A visual version of this model for Prolog
representation and tracing is implemented in the Symbolics Prolog tracer
[S] The main problem with this approach is that rather than showing the
search in the SLD tree, which is the real execution model of Prolog, it gives
a naive and nonaccurate view of Prolog as a procedural language. In an
attempt to “tell the true story about Prolog”, Bundy et al., have devel-
oped a visual tracer for a selected “Prolog story” [5], Dewer and Cleary
have provided a visual tracer with zooming capability that displays Prolog
execution in detail [2], and Rajan has developed a tracer that highlights
the relevant portion of the code and displays the unification procedure
while the programmer is stepping through the program [2]. Eisenstadt,
Brayshaw, and Paine have enhanced and extended the Byrd box model to
th’e point where it represents more accurately the actual execution model
of Prolog [5]. Their system, which is probably the most advanced visual
tracer for Prolog, incorporates the box model within an AND/OR tree.
The transparent prolog machine (TPM) developed by Eisenstadt et al.
includes facilities for both live and post-mortem tracing modes, selective
highlighting, zooming, and replaying.
The main limitation of all these systems is that they are visual tracers,
yet not complete debuggers. This presents the following problems: First,
because there is no facility for break-point insertion, execution to break-
points, stepping, and continuation from a break-point, the user is limited in
his capability to control the program through the debugger and to interact
w-ith the debugger. Second, the tracer supplies the user with a limited, post-
mortem, view of the program. Some tracers such as the TPM include a
live-mode display that can be interrupted upon the detection of a bug. This
is still very limiting in terms of user ability to interact with the debugger,
control the execution, and monitor the display of the executing program.
This limitation results in a lack of correspondence between the display and
the actual portion of the program that is currently executed.
An advanced visual debugger can include two more facilities that are not
available in current visual tracers. The first is a facility to interact with
the debugger directly through visual representation and not through the
code. This is an extension of the principle of object sensitive menus used
in advanced graphical users interfaces. It is implemented in our system
as an option that enables the user to define the insert break-points using
the display of the SLD tree. The second is a facility to change the search
mode of the interpreter. In our system it is implemented as an option that
enables the user to select a node in the SLD tree and direct the interpreter
to continue interpretation from this node. In terms of Prolog debugging,
this is an important facility because it enables reverting from a depth-first
132 TAMIR ET AL.

search to a breadth-first search or to a hybrid-mode search [lo]. The utility


of this facility is that it enables the identification of cases where reordering
the clauses changes the result of execution. In addition, this facility can
be extended easily and used in a visual debugger for a parallel Prolog
interpreter.
This paper describes the first comprehensive visual Prolog debugger.
PROVIS, the visual debugger for pure Prolog, facilitates interaction with
the program through a graphic interface. The user can insert break-points
in the code and execute or step the program to and from break-points. The
major advantage of the debugger is that the programmer can relate his code
to the display on the screen, coalescing Prolog and the theory of predicate
calculus. The graphical display, enhances the understanding of the specific
way in which a Prolog program proceeds through each predicate trying to
satisfy a goal.
Furthermore, the debugger displays the resolution tree and allows the
user to insert break-points directly on the tree. In addition, it enables the
programmer to explore the various paths of the tree at run time. This fea-
ture, referred to as debugging on the tree, allows for abandoning redundant
paths and continuing along the path of interest. Problems evolving from
the specific search technique applied by Prolog and the lack of the “occur
check” can be detected by debugging the SLD tree.
We have selected pure Prolog in this research because it is free from
operating-system constraints and its execution follows the theoretical Pro-
log execution mechanism.

2. PROLOG INTERPRETATION

At the syntax level, a Prolog program is a set of Horn clauses: A clause


with a positive literal and no negative literals is referred to as a fact; a
clause with one positive and at least one negative literal is referred to as
a rule; a unique clause containing only negative literals is referred to as a
query.
The Herbrand theorem and the Herbrand universe form a base for proof
by refutation, which is used by most modern mechanical theorem-proving
systems [8]. A ground instance of a clause C of a set of clauses S is obtained
by replacing variables in C by members of the Herbrand universe of S.
According to the Herbrand theorem, a set of clauses S is unsatisfiable if
and only if there is at least one finite unsatisfiable set S’ of ground instances
of clauses of S. In the process of proof by refutation, the Prolog interpreter
is trying to identify an unsatisfiable set of clauses. This is done using the
resolution inference rule.
The underlying semantics of Prolog is that of proof by refutation of
A VISUAL DEBUGGER FOR PURE PROLOG 133

first order logic. However, Prolog is using an inference rule that includes
unification and binary resolution rather than using modus ponens.
‘Unification is a process that consolidates two literals by substituting
ter:ms for variables in the literals. The list of substitutions is called a
unifier. If the unifier is applied to both literals, the literals become equal.
.Let p be a literal and let R and S be two sets of clauses. The binary
resolution principal implies that one can infer {RvS} given {pvR} and
(1;pvS).
Although the semantics of different Prolog systems deviate very little
from each other (most systems perform a depth-first search on the SLD
refutation tree [4]), the pragmatics and underlying implementation mecha-
nisms vary greatly. Some systems compile Prolog code directly to a specific
machine architecture. Other systems compile Prolog code where the target
system is an abstract machine such as Warrens abstract machine [8]. The
use of an abstract machine allows any architecture that has the abstract
machine implemented on it to run the Prolog system. Other Prolog systems
are interpreted, they maintain their own data structures, and have action
sequences for Prolog code as opposed to several machine instructions.
The next sections describe the Prolog model of interpretation in more
details.

%?..I. Resolution, Unification, and Substitution


The resolution principle removes a complementary pair of literals from
two clauses and constructs the disjunction of the remaining literals [4]. For
example consider the clauses Cl = {avb} and C2 = {lavc}. These two
clauses can be resolved, resulting in a clause C’s given by Cs = {bvc}. The
clause Cs is called the resolvent of Cl and CZ.
A set of clauses S is unsatisfiable if there is not interpretation 1 such that
S is true under I. An empty clause is logically equivalent to an unsatisfiable
set of clauses.

DEFINITION2.1. Given a set of clauses S, a deduction by resolution of


C from S is a finite sequence Cl, Cz, . . . , Ck of clauses such that each Ci is
either a clause in S or a resolvent of clauses preceding C’il and Ck = C.
A deduction of empty clause from S is called a refutation or proof of S.

Given a Prolog program consisting of a set of assumptions and a query,


the resolution refutation procedure adds the negation of the query to the set
of assumptions and then attempts to derive an empty clause. The resolution
refutation graph is a pictorial representation of one possible deduction of
empty clause from the query and the assumptions. That is, resolution
134 TAMIR ET AL.

refutation graph represents one possible solution. The resolution refutation


tree is a graphical representation of all the possible deductions of an empty
clause from a query and a set of assumptions. That is, the resolution
refutation tree represents all the possible resolution refutation graphs for
a given set of assumptions and a query. The SLD resolution tree is a
particular refinement of the resolution refutation tree [4]. It is formed by
unifying the negation of the query with all the clauses and then proceeding
in the same manner with the resultant clauses until the tree is exhausted.
The Herbrand theorem requires that the refutation be performed on
ground instance of clauses [8]. Furthermore, the resolution principle as
stated in this paper can eliminate a complementary set of clauses only if
they are identical. Generally, the clauses in the Prolog program are not
ground clauses; they may contain variables. Moreover, several instances of
the same clauses may contain different terms. Thus, the inference proce-
dure of Prolog includes a step of unification, which attempts to substitute
variables in clauses so that they will match. In order to ensure that the
resolution refutation process implemented by Prolog relates to ground in-
stances of clauses, the substitution must comply with the following rule:

RULE 1. A variable can be substituted by a term, i.e., another variable,


constant, or function. If a variable is substituted by a function, then the
function should not contain the same variable.

DEFINITION 2.2. A substitution is a finite set of the form {tl/q, . . .,


t,/v,}, where every Vi is a variable, every ti is a term different from ui,
and no two elements in the set have the same variable after the stroke
symbol [4].

OCCUR CHECK. During the substitution of a variable V with a func-


tion f ( ), a check whether f( ) contains V or not should be implemented.
If f( ) contains V, then the substitution is not valid. For example, in the
absence of an occur check, unifying X and f(X) produces an infinite term
f (f (f (f (. . .)))). Due to th e cost of implementing this search, many Prolog
interpreters, as well as the interpreter reported in this paper, do not include
the occur check.

2.2. Searching the SLD Tree

The interpreter constructs the SLD tree and a searches for solutions
(empty clauses) on the tree. Because the SLD tree may be infinite, a
system employing depth-first search on the tree is not complete, whereas
a system employing breadth-first search is complete in the sense that it
A VISUAL DEBUGGER FOR PURE PROLOG 135

finds every existing solution [8, lo]. The problem, however, is that the
amount of resources required for breadth-first search grows exponentially
with the depth of the search. In contrast, the amount of resources required
to implement a depth-first search is a linear function of the depth level [lo].
For this reason, the search implemented by Prolog is a depth-first search
procedure. After finding one solution or reaching a dead end, the program
has to back up and search for alternative routes. Thus, a backtracking
version of depth-first search is employed [IO].

2.3. The Naive Model of Prolog Execution


Many textbooks and Prolog training courses assume that the Prolog
programmer is familiar with a procedural language. Moreover, trying to
address the lowest common denominator, these books do not present the
actual relationship between Prolog and first order logic. Instead, they are
trying to establish some mapping from Prolog to procedural languages and
th’en use this mapping and the concepts of procedural languages to explain
th,e execution model of Prolog. The main components of the mapping are:

1. Clauses and axioms are mapped to “IF” statements.


2. A set of clauses with the same positive literal is mapped to a proce-
dure.
3. Goal invocation and resolution is equated to procedure call.
4. A clause containing a negative atom with the same predicate as the
predicate of its positive atom is considered as a procedure with re-
cursion.
5. Unification is explained in terms of parameter passing with dynamic
memory allocation.

This mapping is not accurate. Moreover, some elements of Prolog such


as, backtracking cannot be mapped directly to syntactical elements of pro-
cedural languages. The result is that the programmer is presented with a
distorted and naive view of Prolog. The Byrd box model of Prolog shares
some of these misconceptions; hence, many of the existing tracers for Pro-
log, including the visual tracer described in the foregoing text and the first
versions of the Prolog Transparent Machine, are not adequate as program
tracers for experienced and well trained Prolog programmers. The visual
debugger presented in this paper graphically presents the actual and accu-
rate model of Prolog execution. That is, a state-space search in the SLD
resolution tree.
136 TAMIR ET AL.

Fig. 1. Tree structure for storing predicates

3. IMPLEMENTATION OVERVIEW

3.1. The Interpreter


The main functions of the interpreter are to check the syntax of the
program, create appropriate storage structures for the clauses, and perform
the tasks of unification, resolution, and substitution.

Grammar Checking
The Prolog program is read in by the interpreter and the clauses are
examined for any illegal pattern or usage. Any deviation from the right
syntax is flagged as an error. On finding an error, the program transfers
control to a print-error procedure that outputs the actual line in which the
error has occurred.

Generating Storage for Clauses


A clause consists of one or more predicates. Each predicate may contain
terms. Some of these terms may contain additional terms. This is referred
to as levels of term nesting. The data structure used for the storage of
clauses is a tree. The different levels of the tree are used to represent the
levels of nesting. For example, consider the predicate p(X, f(a, b), Y). The
variable X, the function f, and the variable Y represent the first level.
The second level contains the constants a and b in the function f. Figure
1 shows the tree structure used to store the preceding predicate.
Additional data structures used by the interpreter/debugger are:

??Predicate-structure: A linked list used for storing individual predicate


information.
. Rule-structure: A linked list containing indices of all the predicates
in the same clause.
A VISUAL DEBUGGER FOR PURE PROLOG

o Resolvent-stack: A stack used for storing values of resolvent clauses.


This stack facilitates backtracking, because it tells which clause to
use after a solution or a dead-end has been encountered.
?? Substitution_table: Contains a list of variables and the current sub-
stitutions applied to these variables.
?? Graph-stack: A stack for storing coordinates of various clauses on
the paint window.
a Predicate-Structure: An array of structures that stores all the pred-
icates of a single clause.

Unification and Resolution


The process of resolution is implemented with the use of the Resol-
vent-stack, which stores the values of clauses that have been resolved with
the query or with other resolvents. Initially the negation of the query is
pushed onto the Resolvent-stack. At each consecutive stage, the clause at
the top of the Resolvent-stack is removed (“popped”) from the stack and
tested for unification with each of the clauses of the program. If there is a
successful resolution, then the new resolvent is pushed onto the stack. This
process continues until the top of the stack contains an empty clause or the
clause at the top of the stack cannot unify with any clause of the Prolog
program. The algorithm then backtracks and tries to pick up other possible
solution paths by removing the next element of the stack. The procedure
terminates when the stack is empty. Discovering an empty clause at the
top of the Resolvent-stack is indicated by an output of the character “Y”
to the text window.

3.2. The Debugger


The debugger is implemented with the help of condition checks on the
stack storing the predicates. Check points are put when a particular pred-
icate is being handled in the stack. These check points indicate that the
process has to be stopped or resumed. The various debugging features
incorporated are:

1. Stop at a particular source line, i.e., a break-point.


2. Resume execution from a break-point.
3. Single step through each instruction.
4. Display values of variables at a break-point.
5. Execute the program.
6. Clear a break-point.
7. Debug or explore various paths on the resolution tree.
8. Quit the program.
138 TAMIR ET AL.

Resolution Tree
The software draws the resolution tree as the Prolog program executes.
The predicate information along with the various substitutions are stored
in the Substitution-table. These predicates are displayed in the form of a
tree on an XView canvas. The tree encapsulates all the solution paths of
a given set of clauses. Starting from the query, it displays the branches
representing the different rules, the various resolvents, and the solutions.
Another facility provided is “debugging on the tree.” The user can
select any node on the tree by clicking the mouse button. Upon selection
of a node, the program continues evaluation from the selected node. This
gives the user the flexibility to ignore paths that are potentially leading to
dead-ends or to pursue a specific path of interest.

3.3. The Graphical User Interface


The GUI is implemented in C using XView under X-Windows. Figure 2
shows the XView interface, which encapsulates the following objects:

1. A canvas to draw the resolution tree. A separate routine handles the


drawing of the tree on the canvas. The various predicates and their
corresponding substitutions are recovered from the stack and proper
coordinates are decided for the printing of these values on the screen
in the form of a tree. The tree branches are drawn on the screen as
the program executes. A dead-end in the tree (unification failure) is
denoted by a small empty circle. A solution, is denoted by a small
empty rectangle.
2. Text window for displaying the Prolog source code. This window
displays the Prolog program. Break-points may be placed on any
source line in this window. They are indicated by the symbol “j.”
3. Panel items for various debugging commands. The panel items are
the “stop,” “run,” “continue,” “step,” and “quit” buttons used in
running and debugging the program.
4. Text window for the display of messages and solutions. The event of
finding a solution is denoted by sending a message Y to this window.
5. Text window for the display of variable substitutions. This window is
used to get values of variables used in the program. The values may
be intermediate values, e.g., when the program halts temporarily at
a break-point, or it can be the final values at the termination of the
program.

Because the number of levels and the branches in a Prolog program is


unpredictable, there is a possibility that the graphical representation of the
SLD tree is too detailed. To solve this problem, the facility of zooming into
A VISUAL DEBUGGER FOR PURE PROLOG 139

I
5
f
$
140 TAMIR ET AL.

the tree, i.e., drawing a part of the tree, is provided. Under this option, as
soon as the program detects a dead-end or a solution, it erases the preceding
part of the tree and displays only the current node of interest. At any point
in time, the user is able to either see the entire tree or concentrate on the
neighborhood of the node currently being evaluated. For “debugging on
the tree,” the user manipulates the SLD tree with the help of the mouse.
This can be done under the “full tree” option as well as under the “part
tree” option.

4. EXAMPLE PROGRAMS

In the following examples, as well as in PRIOVIS, a first order logic


syntax is used rather than the French-style Prolog syntax. Three programs
are presented. Program one shows a simple instance of an infinite loop
(branch). Program two, illustrates the interaction of the user with the
debugger and the relations between a Prolog program and a production
system. Program three demonstrates some of the advanced features of the
debugger.

4.1. Program One


Program one contains a single rule (RI), which translates to the clause
{p(X),lp(X)}, and a query (Q), yet it runs into an endless loop. The
contents of the program are

Rl.P(X) + P(X).
&:&a)?
Performing unification and resolution, the negation of the query, i.e.,
-p(a), unifies with the clause and results in the clause {Tp(a)}. This
results in an endless loop because it resolves with the same rule repeatedly.
The program terminates when the resources are exhausted or when the
“quit” option of the debugger is selected. Figure 3 shows a snapshot in the
execution of program one. Note that the break-point has been set on RI.
Under the “naive” representation of Prolog, this program would be de-
scribed as a recursive procedure with no termination condition.

4.2. Program Two


Program two is a simple program similar to example programs that
appear in textbooks that teach Prolog using the “naive approach.” We
include it in this paper in order to exemplify the SLD tree of such a program
and to demonstrate interaction between the user and the visual debugger
A VISUAL DEBUGGER FOR PURE PROLOG 141

h 8
P

8
\ 0 P
142 TAMIR ET AL.

in this set of problems. This program can be considered also as an example


of a “toy production system” or a “toy expert system” with a rule base
(Rl-R2) and a fact base (R3-R.6). Hence, the programmer can use the
debugger to discover the difference and relations between the inference
engine of some expert systems and the inference procedure of Prolog.

Rr: grand(2, Y), father(X, 2) + greatg(X, Y).


Ra: father(X, Y), father(Z, Y) + grandg(X, Y).
R3: father(bob,rick).
Rd: father(senior,david).
Rg: father(david,bob).
Rc: father(bob,nancy).
Q: greatg(G,nancy)?

The program contains four clauses in the form of “father(X, Y),” which
can represent the relation “X is the father of Y.” In an expert system
paradigm, these clauses are referred to as facts. The clauses, RI and Rz
can be used to define the relations of grandfather and great-grandfather. In
production system terminology RI and Rz are referred to as “rules.” Solv-
ing the query results in identifying the great-grandfather of nancy provided
that there is enough information about him in the fact base.
Figure 4 shows a snapshot of executing the program under PROVIS.
The current goal in this snapshot is to find X, W, and V such that X is
the father of W, W is the father of V, and V is the father of nancy. To save
space, the program has been rewritten so that each predicate and variable
is represented using its distinguished prefix. Thus “f” stands for father,
“n” stands for nancy, “gra” denotes “grandg,” and “gre” denotes “greatg.”

4.3. Program Three


Program three is used to demonstrate some the features of the debugger.
This includes the ability to modify the order of the execution through tree
manipulation operations and the facility of zooming into the tree to display
just the part of main interest. The listing for program three is:

Ri: p(X, Y) -+ P(Y X).


R2: da, f~).

Q : P@J,4.
In this case RI states that p is a reflexive relation and R2 states that p
holds for (a, b). The query Q tries to identify if there is a Z such that p
holds for (b, Z). The trivial answer is Z = a. However, due to the fixed
control structure of Prolog the program runs into an infinite brunch and
A VISUAL DEBUGGER FOR PURE PROLOG 143

L
-
144 TAMIR ET AL,.

terminates with no solution after exhausting its resources. Reordering the


clauses RI and Rz would result in a repeated set of correct answers. Again,
the execution stops when the interpreter runs out of resources.
Figure 5a shows a snapshot in the execution of program three using
the step option of the debugger. The user discovers that the program
contains an infinite brunch and decides to try another node of the tree.
The canvas location that says --p(b, 2) is pointed to by the mouse and
selected by clicking the mouse button. This suspends the tree traversal
on the current path and starts traversal from the location that the user
has selected. Figure 5b shows that as a result of selecting this branch, a
solution is identified. The user now understands that the problem can be
fixed by reordering the program clauses. Figure 5c shows a snapshot of the
execution of the program after reordering the clauses. The button “Show
Substitution” identifies the solution Z = a.
As previously explained, the software provides the user with the option
of drawing a part of the tree. Under this option, if a solution or a dead-end
is found in node T, then the part of the tree that has been explored before
the generation of node T is erased from the screen. Figure 5d shows the
execution of the modified version of program three with this option.

5. CONCLUSIONS

The software performs the functions of a visual debugger for Prolog. The
basic functions, such as setting up break-points, single stepping through in-
structions, printing variable values, resuming execution from a break-point,
clearing break-points, and quitting the program, are provided along with
the interpretation of Prolog. All the above-mentioned features incorpo-
rated in an XView graphical user interface that allows the use of windows,
panels, and a drawing canvas. The canvas displays the resolution tree and
gives the user a picture of the unification, resolution, and the substitution
process. In addition, the user can manipulate the SLD tree by selecting
various paths for traversal and abandoning searches along specific paths.
Many researchers have identified that logic programming languages-
Prolog in particular-have a high potential for parallel processing [8]. As
a result, several interpreters for parallel Prolog have been implemented.
Common to most of these interpreters is the approach that some parts of
the SLD tree are explored simultaneously by different processes on differ-
ent machines. Intuitively, parallel Prolog can be viewed as a set of tasks
executed by several processors. Each task consists of the original Prolog
program with a different query.
Our current effort is the design of an interpreter and a visual debugger
for parallel Prolog. In addition to facilitating the debugging of a paral-
A VISUAL DEBUGGER FOR PURE PROLOG

(b)

Fig. 5. Program three in execution.


146 TAMIR ET AL

(4 ,

Fig. 5. Cont.
A VISUAL DEBUGGER FOR PURE PROLOG 147

lel Prolog program, this debugger will enable monitoring the process of
distributing the tasks among the processors. It can lead to an interac-
tiv,e parallel execution of Prolog, where an operator decides which node to
explore next and which machine should be used for the exploration.

RE:FERENCES

1. K. Araki, 2. Furukawa, and J. Cheng, A general framework for debugging, IEEE


Software, May:14-20 (1991).
2. M. Brayshaw, M. Eisenstadt, and J. Paine, The Transparent Prolog Machine-
Visualizing Logic Programs, Intellect Books, Oxford, England, 1991.
3. H. M. Brown and J. Hershberger, Color and sound in algorithm animation. IEEE
Computer, December:52-63 (1990).
4. C. L. Chang and R. C. T. Lee, Symbolic Logic & Mechanical Theorem Proving.
Acaedmic Press, New York, 1973.
5. M. Eisenstadt and M. Brayshaw, A practical graphical tracer for Prolog. Int. J.
Man Machine Studies 35:597-631 (1991).
6. M. M. Goalie and B. W. Wah, Efficient reordering of Prolog programs. IEEE IDrans.
Knowledge & Data Eng. December:470-473 (1989).
7. S. Isoda, T. Shimomura, and Y. Ono, VIPS: A visual debugger. IEEE Software,
May:8-19 (1987).
8. P. M. Kogge, The Architecture of Symbolic Computers. McGraw-Hill, New York,
1991.
9. A. D. Malony, D. H. Hammerslag, and D. 3. Jablonowski, Traceview: A trace
visualization tool. IEEE Software, September:19-28 (1991).
10. J. Pearl, Heuristics-Intelligent Search Strategies for Computer Problem Solving.
Addison-Wesley, Reading MA, 1984.

Received 1 January 1994; revised 24 June 1994

You might also like