Академический Документы
Профессиональный Документы
Культура Документы
La.nguages,
Programming
by William R. Mallgren
Ehud Y. Shapiro
Publisher's note: This format is intended to reduce the cost of publishing certain
work in book form and to shorten the gap between editorial preparation and the
final publication.
photographing the text of this book directly from the author's typescript or
word-processor output.
This dissertation was presented to the Faculty of the Graduate School of Yale
University on May 1982.
Apart from some stylistic changes and the correction of typographical errors, the
only difference in content is in Sections 2.1.3 and 4.5. To these sections there has
been added a description, without proof, of results obtained in {88,
91].
The thesis research was supported by the National Science Foundation, grant
no. MCS8002447.
Bibliography: p.
Includes index.
( Computer
QA76.6.S49 1983
001.64'2
82-24992
ISBN 0-262-19218-7
MIT
Pre.e
0262192187
SHAPIRO
ALGORITHMIC PROGM
"I"" "II
Series Foreword
The Distinguished Doctoral Dissertation Series is a welcome outgrowth
of ACM's annual contest, co-sponsored by The MIT Press, for the best
doctoral dissertation in computer-related science and engineering.
During the judging process that is designed to select the annual
winner, it has inevitably developed that some of the theses being con
sidered in the final round are of such high quality that they also deserve
pUblication. This book is one of those dissertations. In the judgment of
the ACM selection committee and The MIT Press, it truly deserves
special recognition as a Distinguished Doctoral Dissertation.
Dr. Ehud Shapiro wrote his thesis on "Algorithmic Program Debug
ging" while at Yale University. His thesis advisor was Dr. Dana
Angluin, and the thesis was selected by Yale for submission to the 1982
competition. The Doctoral Dissertation Award committee of ACM rec
ommended its publication because it productively combines elements
of programming languages, environments, logic, and inductive infer
ence to produce effective debugging aids. Its use of the PROLOG
language provides an efficient implementation of the debugging algo
rithms.
Walter M. Carlson
Chairman, ACM Awards Committee
To Karl R. Popper
for his inspiring intellectual courage and clarity
and
to my parents, Shimon and Miriam
for bringing me up knowing that
the world is a great place to be
Acknowledgments
First and. foremost,. this thesis owes its shape and content to my
.
advisor, Dana Angluin. She has directed my research since I came to
Yale, and has had a great influence on what I have accomplished in
these years, and what I know today.
She also
He gave me
Without
Alan's encouragement, I would not have had the nerve to make some
of the bold claims I have made, and his flamboyant manner helped to
counter-balance Dana's caution and serenity.
I got a lot of support from the people of the logic programming
community.
Byrd,
with Lawrence
Bob
-ix-
while.
Together
with
Alan
Perlis,
he
showed
me
that
-x-
provided me.
National
Science
Foundation,
whose
grant,
numbered
Contents
Chapter 1: Introduction .
1.1 The problem
1.2 Results . .
'. . .
1
1
2
6
8
1.3.3 Program testing .
10
12
13
2.1.1 Computations . .
2.1.2 Semantics.
15
16
17
19
22
23
23
2.2.3 Control. .
2.2.4 Side-effects
.
.
24
26
"'
28
28
2.2.6 Meta-programming
30
32
3.2.2
single-stepping
algorithm
33
37
'37
for
incorrect procedures.
'
diagnosing
39
40
-xii-
Divide-and-query:
algorithm .
42
diagnosis
query-optimal
44
48
51
51
54
59
59
63
66
73
74
75
76
77
81
. . . .
82
82
83
85
89
89
90
95
97
104
104
109
1 15
118
-xiii-
118
119
127
138
138
Chapter 6: Conclusions
. . . .
as
a research tool .
1 42
144
1 43
1 46
1 47
157
. . .
1 57
130
158
1 59
162
164
.........
166
1.1 Inferring insertion sort
. . . .
166
17 4
185
187
190
190
191
19 4
195
196
198
200
-xiv-
200
204
e.
210
211
213
References
215
Name Index.
231
Algorithms
Algorithm 11
stepping
Algorithm 2:
. . . .
and-query. . . .
Algorithm
Algorithm
Algorithm
Algorithm
. .
. . . .
39
. . . .
. . .
46
53
63
refinement graph
91
of
the
128
141
146
FigUl'es
debugging algorithm.
programming
concepts
in
logic
. . . . . . . . . . . .
17
20
20
41
121
186
Programs
16
29
30
Program 4:
stepping . . . . . . . . . . . . . . . . . . . . .
40
48
Program 6:
query .
. . . . . . . . . . . . . . . . ... . . .
49
55
57
64
65
67
78
17:
pruning
refinement graph
breadth-first
.
99
109
115
118
search
of
the
129
Chapte r 1
INTRODUCTION
1.2 Results
Figure
1:
It has been suggested that one way to eliminate the need for
debugging is to provide a correctness proof of the program. As Naur
and Randell say (in [70J, p.51, from [41]):
"IWhen ] you have given th e proof of correctness, ... Iyou) can dispense
with testing altogether."
artifact;
and
any
complexity is imperfect.
human
The output
[of
of
suff icient
size
and
system
language,
data
structures,
control
structures
and
being
developed through
a sequence of executable
prototypes
10
facilities, and
"vertically" ,
through
a deepening or existing
facilities..."
11
12
13
Apprentice at MIT [81, 83, 92], and Soloway et ale [95]. Both have
developed a bug diagnosis system which can identify a restricted class
of bugs. To do so, the system is supplied with a plan for the intended
program, and infers the existence and type of bugs in the program by
performing some kind of pattern-matching between the plan and the
program. Both systems are at an experimental stage, and are
currently applicable only to a narrow class of bugs.
Work in inductive inference is surveyed separately in Section 4.1.
1.4 Outline
14
Chapter 2
CONCEPTS OF LOGIC PROGRAMMING
AND PROLOG
16
among others.
studied by Shapiro
[91].
The basics
definite clause8,
which are
-+-
B 'B ,
l 2
,B k
kO
where the A and the B's are logical atoms, also called
goals.
Such a
1.
isort([X/Xs],ys)
isort([],[]).
+-
isort(Xs,Z8), insert(X,Zs,Ys).
insert(X,[Y1Ys],[X,Y1Ys])
insert(X,[Y1Ys],IYlZ8])
insert(X,[],[X}).
+-
+-
X Y.
X>
Y, insert(X,Y8,Z8).
The term
17
the term [X111 stands for a list whose head (car) is X and tail (cdr) is
Y. The results of unifying the term [A,BIx] with the list [1,2,3,4] is
A=I, B=2, X [3,4], and unifying [Xll1 with [a] results in X a,
Y:
[].
Definite clauses
Procedure calls
Goals
Binding mechanism,
data selection and construction Unification
Nondeterministic goal reduction
Execution mechanism
Figure 2:
2.1.1 Computations
+-
18
--
IThe usual definition of derivation allows any atom in the goal to be resolved
with a clause, not necessarily the first one. Apt and van Emden (7) showed that
the restriction of derivations to resolve the first atom only does not violate the
completeness of the proof procedure. We adopt this restriction to simplify the
definition of total correctness below.
19
2.1.2 Semantics
..
20
<isort([2,lj,L),
(isort([X1Xsj,Ys) +- isort(Xs,Zs), insert(X,Zs,Ys)),
{X-+2,Xs-+[lj,L-+Ys} >
isort([lj,Zs), insert(2,Zs,Ys)),
(isort([X1IXs1j,Ys1)
isort(Xs1,Zsl),insert(X1,Zsl,Ys1))
{X1-+1,Xs1-+[j,Zs-+ Ys1} >
isort([],Zsl), insert(l,Zsl,Zs), insert(2,Zs,Ys)),
isort([], 0),
{Zsl-+[]} >
insert(l,[],Zs), insert(2,Zs,Ys)),
insert(X2,[],[X2j,
{Zs-+[X2j,X2-+1}
<insert(2,[lj,Ys)),
(insert(X3,[Y3IY3sj,[Y3IZJs])+-X3>Y3, insert(X3,Y3s, ZJs)),
{X3-+2,Y3-+1,Y3s-+[j,Ys-+[1IZJs]} >
<(2) 1,insert(2,O,ZJs)), 2>1,0 >
<insert(2,[],ZJs), insert(X4,[],[X4]), {ZJs-+[2j,x4-+2}
<D,D,O>
+-
Figure 3: An
example of a refutation
isort([2,1j,[1,2])
isort([lj,[l])
isort(O,[])
insert(1, [],[1])
insert(2,[lj,[l,2])
2>1
insert( 2,[],[2])
Figure 4: An
example of
refutation
tree
21
H{P}. n
A program that is everywhere terminating over its domain, and
is correct and complete in M is called totally correct in M. The
target of our debugging and synthesis algorithms are totally correct
22
programs.
2.1.3 Complexity measures
Definition 2.3:
2.4:
23
Using the results of Chandra et. al 123], one can characterize the
complexity of logic programs in terms of deterministic complexity
measures.
2.2 Prolog
execute
24
the program for the first clause whose head matches or unifies with
the goal. The unification process [84] finds the most general common
instance of the two terms, which is unique if it exists. If a match is
found, the matching clause instance is then activated by executing in
turn, from left to right, each of the goals (if any) in its body. If at any
time the system fails to find a match for a goal, it backtracks, i.e. it
rejects the most recently activated clause, undoing any substitutions
made by the match with the head of the clause. Next it reconsiders the
original goal which activated the rejected clause, and tries to find a
subsequent clause which also matches the goal."
25
the occur check is not felt in most programming tasks, including the
development of the systems described in this thesis. Colmerauer [29]
describes a theoretical model of Prolog without the occur check, based
on unification over infinite trees.
The complexity measures defined for logic programs are
26
2.2.3 Control
+-
P, !, fail.
where fail is a goal that fails ( i.e. has no clauses defined for it) . The
not program uses the meta-variable feature of Prolog, that allows
goals to be determined dynamically, at runtime; it is similar to passing
procedure names as parameters in a conventional programming
language. Tired of being accused that Prolog's not is not really not,
the implementors of Prolog-lO switched to "\+" instead, hoping that
27
as:
(P Q ; R) - P, !, Q.
(P Q ; R) - R.
28
2.2.4 Siderrects
[1-a,1-b,1-c,1-d,2-a,2-b,2-c,2-d,3-a,3-b,3-c,3-d]
29
is not the most elegant, but no Prolog user ever needs to look at it.
The implementation of bago! in Program 2 is a simplified version of
its implementation in Prolog-l0.
bago!(X,P,Xs) +asserta(item{ '$bag )), P, asserta( item(X)), fail;
rap([],xs), nonempty{Xs).
'
reap(Xs,Ys) +
retract(item(X)), !,
(X ='$bag' -+- Xs=Ys ; reap([XIXs],Ys) ).
nonemply([_I_])
Program 2: An
implementation of bago!
bagof(X,(member(X,[1,2,3]),
member((X -Y), [I-a,2-a,2-b,3-b))),S).
S =[1,2],
Y=a;
{2,3],
Y=b
30
1-
bagoj(X,yt(member(X,[1,2,3]),
member((X-Y),[1-a,2-a,2-b,3-b])),S).
= [1,2,2,3]
2.2.6 Meta-programming
"
"I'd rather write programs that help me write programs than write
programs."
- An anonymous meta-programmer
Considering the goals of this thesis, the most important aspect of
Prolog is the ease with which Prolog programs can manipulate, reason
about and execute other Prolog programs. Program 3 below shows an
interpreter for pure Prolog, written as a pure Prolog program. It uses
the system predicate clause(p'Q), which functions as if the program is
reresented as a list of unit clauses clause(P,Q)- for any clause P-Q
in it. A unit clause P- is represented as clause(p,true)-, a
conjunctive
goal
Al', ... ,An_l'An
is
represented
as
(Al,(,(,(An_l,An))))
solve(true).
solve((A,B)) - solve(A), solve(B).
solve(A) - clause(A,B), solve(B).
Program 3: An
31
[1,2,2,3,4,6]
Chapter 3
PROGRAM DIAGNOSIS
33
relevant for d iagnosing the bug. They seem to function rather well as
a rep laceme nt, or enhancement, to the standard trace pac kage of an
advanced programming environment.
From another point of view , however, these algorithms open u p
the way for a much more automated form of debugging, since they do
not necessarily rely on a human age nt to answer the ir queries: stored
answers to previous queries, a previous version of the program that is
known to work, assertions concerning the input/output behavior of
procedures - all can be used to answer t he queries in place of the
human programmer, and help locate the bug.
34
and its "code" . In this abstract setting we do not specify what that
code is, but assume that the language has a computable interpreter,
that maps this code into a class of legal behaviors for that procedure,
which we describe via top level traces [16].
A top level trace of a procedure P on input x that returns y is a
finite ( possibly empty ) ordered set of triples:
{<Pi,xi'Y >'
I
Where the p 's are procedure names, and the x's and V's are vectors
over some domain D, not containing the symbol 1-. The intended
interpretation of such a top level trace is as follows: if the set is
empty, it means that the procedure p, on input x, has a legal
computation that returns Y without performing any procedure calls;
otherwise it means that p, on input x, has a possible computation that
calls PIon Xl' and if this call returns YI' then P calls P2 on x2' and if
this call returns Y2 then... , then P calls Pk on xk' and if this call
returns Yk' then p returns y.
The restriction that the top-level trace is ordered assumes a
sequential interpreter. This restriction needs to be relaxed to handle
concurrent programming languages, and we suspect that most of the
techniques of the diagnosis algorithms will carry through. The
programming language can be nondeterministic ( with bounded
nondeterminism) , and in such a case for each triple <p,x,y> there
can be only finitely many legal top level traces.
We describe legal computations of a program via computation
trees. Let P be a program. A partial computation tree of P is a
rooted, ordered tree whose nodes are triples <p,x,y> , where P is a
procedure name, X and yare vectors over D, and for every internal
node <p,x,y> in T with sons S, S is a legal top level trace of
<p,x,y> , where P is a procedure in P. A tree T is a complete
computation tree of P ( computation tree for short ) if it is a partial
computation tree of P in which all leaves have empty top level traces.
Complete computation trees represent successful computations, and
correspond to refutation trees in logic programs.
A tree T is a reachable computation tree of P if it is a partial
35
36
37
plus(O,Y,Y).
plus(X O, Z)
plus(X,O, Z).
plus(s(X),Y,s(Z))
plus(X,Y,Z).
,
+-
+-
38
Definition 3.1: A
f(X,l}
+-
integer(2x X) , 1(2xX,l}.
{<I, X, 1>
i s incorrect in the interpretation M
integer } , since <I , 0.5, 1 > is not in M, but its top
{ <I, 1 , I>} is. Theorem 3.2 shows that if a program
com putation that retu rns an incorrect outp ut then it
incorrect procedure.
=
I X is an
level trace,
has a fi nite
contains an
Theorem 3.2:
Let P be a program and M an
interpre tation. If P is not partially correct with respect to
M then P contains a p rocedure incorrect in M.
Proof:
39
tree wh ich is not i n M. Such a node e xists, since the root is not in
By the choice of th is node , all its sons ( if an y) are in M, hence q
covers <q,u,v>. But since <q,u,v> is not in M, it fol lows that q is
incorrect in M. 0
M.
Input :
<q,u,v>.
40
-+
-+
-+
Program 4:
(A-B.
41
A solved goal may still contain variab les, which are interpreted
to be universally quantified. The implementation of query can either
instantiate t he variables before querying the user, or perform a
universal query . In our implementation query(forall,A,V) returns
V tru e if every ins t ance of A is true, or unifies A with s uch a false
instance an d V with false otherwise; the code is shown in Appendix II.
We examine the behavior of fp on the following bugg y insertion
sort prog ram.
isort([XIXs1,Ys)
is o rt([] , O) .
isort(Xs,Zs), insert(X,Zs,Ys).
[2,3,1 ]
and get a wrong result. The tree of this com putation is shown in
Figure 5.
isort([2, 1 ,3], [2,3,1 ])
isort( [ 1 ,3] , [3 ,1])
isort([3] ,[3] )
isort([] , O)
insert ( 3, [] ,[3])
insert( 1, [3], [3,1])
3>1
in sert{ 1,(j ,[1])
insert ( 2, [3, 1 ] , [2 , 3, 1])
23
Figure 5:
42
yes
/p returned a false instance of the first clause of insert. E xamining it
shows that the arguments for the > test are exchanged. We fix t hat
bug , and try isort again,
I ?- isort ([2,1 ,3], X).
x = [1 , 2 ,3]
43
computational complexit y.
Length and depth of computations of the diagnosis algorithms
are measured as a function of the complexit y of the computation
being diagnosed, as defined in Section 3 . 1 . We ignore the cost of
performing a query since we give a separate analy sis of the query
comp lexity for each diagnosis algorithm .
Using' t hese measu res, the worst-case length and depth of the
single-stepping diagnosis algorithm, when diagnosing a computation o f
p on x that returns y, are linear in the length and depth, respectively,
of the fau lty computation. The maximum number of oracle queries it
performs is bounded b y the length of t he computation .
Answering that man y queries can be come a tedious matter if the
comp utation is long. We show that, in the wo rst case, the number of
que ries an y diagnosis algorithm of this t ype requires is of order of the
logarithm o f the n umber of proce dure calls in the computation. In the
fol low ing sect io n we develop an algorithm that achieves this
performan ceo
The lower boun d proof is based on an info rmation-theoretic
adversary argument, and its idea is simple: the most a query can tell
us is t he existence of a bug in a component of the computation tree.
An "ad versary bug" can choose to hide in the larger component o f t he
tree. The best st rateg y against such a bug is to perform queries that
split t he tree into t wo roughly equal components. The result of such a
query n arrows the search space for a bug to one component, and a
sequence o f at most log2 n su ch queries can detect the bug.
We assume that a diagnosis algo rithm for incorrect procedures
u ses a ground oracle for M an d, when app lied to a computation of
any procedure p on input x that returned an output y incorrect in M,
it returns a trip le <q,u,v> not in M.
Theorem 3.3: Let DA be a diagno sis algorithm for
incorrect p rocedures. Then t here is a program P such that
for any n there is an interpretation M and a triple <p,x,y>
with a computation tree of length less than or equal to n, for
which DA on <p,x, y> performs at least log2 n queries.
44
p(o).
p(s(X))
+-
p(X).
Plaisted.
45
3.4:
46
Algorithm 2:
Lemma 3.6:
47
Lemma 3.6:
I(1 ) 1
I(n) 1 + I(n(2b-l)/2b)
We
blog2n 1 + blog2(n(2b-l)/2b)
can be reduced to the inequalit y log2(2b-l)/2b-1 , which holds for
b>1.
The length of each iteration is linear in the size of the remain ing
computation tree. Hence the total length of the computat ion satisfies
the fo llowing recu rrence relation
L( I ) k
L(n) kn
L(n(2b-l)/2b)
for some k>O, that is sat isfied b y the solution L(n)cn, for some
c2b. 0
48
!,
/pm(((A,B),Wab),M,W)
/pm((A,Wa),( Ma,Wma), W), /pm((B, Wb),( Mb,Wmb), W),
Wah is Wa+Wb,
( Wma>=Wmb M (Ma,Wma) ; M (Mb,Wmb) ).
/pm((A,O),(true,O), W)
system(A), !, A; /act(A,true).
/pm((A,Wa),M, W) +clause(A,B), /pm((B, Wb), Mb, W),
Wa is Wb+l,
( Wa>(W+l) /2
M Mb ; M ((A+-B),Wa) ).
+-
-.
+-
-.
P rogram 5 : An
49
The first clause computes the heaviest node returned by the recursive
calls on the sons, and the total weight of the node. The second clause
prunes goals that are in M' or are system predicates. The third
clause solves unit goals by activating a clause, and also decides
whether it is in the upper or lower half of the computation tree, and
returns its output accordingly, as described above.
false solution(A)
writelv(['Error: wrong solution ',A,'. diagnosing ']), ni,
fpm((A,W), _ ,O), % finds W, the length of the computation
handle.....;.. error('false clause' ,X) ;
fp(A,W,X)
write( , !Illegal call to fp'), nl.
+--
...
-+
fp(A, Wa,X)
fpm( (A, Wa ), ( (P+--Q), Wm), Wa),
X (P+--Q) ;
( Wa=l
querY(forall,P,true)
Wal is Wa-Wm, fp(A,Wa l ,X) ;
fP(p,Wm,X) ).
+--
-+
-+
Program 6:
50
isort([X1Xs] ,ys)
isort(O,D).
isort(Xs,Zs), insert(X,Zs,Ys).
insert(X, [Y1Ys],[X,Y1Ys))
X::;;Y.
insert(X, [Y1YsJ,[Y1Zs]) insert(X,Ys,Zs).
insert(X,[],[X]).
If
we
apply
the
single-stepping
computation
it
will
algorithm
perform
In comparison,
16
to
diagnose
queries,
in
the divide-and-query
algorithm needs only four queries in this case to find a false clause.
n.
n.
y.
Theorem
ensures
that
the
length
and
depth
of
the
running time of the program, since the division strategy does not take
into account the amount of backtracking that is needed to construct
the different parts of the computation tree, but their final sizes only.
However, an
O(n log n)
n;
log
some
is n,
additional
arithmetic
operations
and
unifications,
51
x,
on
y,
on
is a correct
terminates and
on
output correct in
is said to
In this
3.3.1 Completeness
A program
<p,x,y>
in
is said to be
M, there
is a
Theorem
3.7:
interpretation.
then
P contains
Let
be
and M an
<p,x,V> in M,
program
<p,x,y> in M for
which every reachable computation tree of P rooted at <p,x,y> is
finite, and there is no such complete computation tree; then P
contains an incomplete procedure. The proof is by induction on d, the
Proof: We have to show that if there is a triple
52
53
Algorithm 3:
54
trees.
We prove by induction on d that the depth of the computation
of ip is at most d+1 , its length is at most dn+ 1, and the number of
queries it performs is at most b(d-l). If d=l, it means that there are
no top level traces for <p,x,y>, hence ip returns immediately
without performing any queries. Hence both the depth .and the length
of ip 's computation are d+l=dn+l=2, and the number of queries
performed is b(d-l)=b(I-l)=O.
Ass u me that the claim holds for d-l, where d> 1 . In this case ip
tries to construct an oracle simulation of the procedure call <p,x>
that returns y; to do this it has to perform at most b existential
queries, by the assumption that the sum of sizes of any top level
traces of any triple in reachable computation trees of <p,x,y> is b.
Following this step, ip either returns or calls itself recursively
with some triple <q,u,v> that finitely fails. By the assumption that
the depth of the computation of p on x is d and its length is n, the
depth of any computation of a triple in the top level trace is at most
d-l , and the maximal sum of their lengths is at most n-l.
By the inductive assumption, the depth of the computation of ip
on <q,u> is at most d and its length is at most (d-l)n+l, therefore
the depth of the computation of ip on <p,x,y> is at most d+l, and
its length is at most (d-l)n+l+n=dn+1.
By the inductive assumption the number of queries performed by
ip on <q,u> is at most b(d-2), therefore the number of queries
performed by ip on <p,x> is b(d-2)+b=b(d-l), and the claim is
proved. D
3.3.3 A Prolog implementation
55
least one goal that imm ediately fails. In the context of logic
programs, Theorem 3.7 says that if a program P finitely fails on a
goal A in M, there there is a goal B in M such that no clause in P
covers B.
Program 7 can detect such goals. It is a direct
implementation of Algor it hm 3.
ip((A,B),X)
!,
( A - ip(B,X) ; ip(A,X) ) .
ip(A,X)
clause(A,B), satisfiable( B) - ip(B,x)
-
;X
A.
satisfiable((A,B))
!,
query( exists,A,true), satisfiable(B).
satisfiable(A)
query( exists,A,true).
-
P rogram 7:
56
isort([XlXs] ,Ys)
is ort([] , m.
+-
isort(Xs,Zs), insert(X,Zs,Ys).
+-
57
query: insert(l,[],[l])? y.
x
insert(l ,[],[l ))
yes
And it finds that insert(l ,[],[l]) is uncovered. We examine the two
clauses for insert, and see that neither of them can cover this goal:
their heads do not unify with it, since they expect a nonempty list in
the second argument. We realize that we forgot the base clause
insert(X, [], [X]).
An improvement of the query-complexity of ip can be obtained
by interleaving the search for a top level trace that is in M, with the
search for the failing goal, as mentioned above. In the best case, this
improvement can be a factor of at most b, where b is the maximum
number of goals in the body of a clause in the program being
diagnosed. In the worst case, the query-complexity will remain the
same. Program 8 contains this improvement, and is the program used
in the systems developed in the following. It is also augmented with
an interface to the error handler, similar to Program 6.
mz'ssing solution(A}
writel([' error: mz's sing solution ',A,'. diagnosing ']), nl,
query(exists,A,true), \+solve(A,true) -ip(A,X), handle error(' uncovered atom' ,x);
write( '!Illegal call to ip'), nl.
+-
..
ip(A,X)
clause(A,B), ipl(B,x) -- true; X A.
+-
ipl((A, B),X)
!,
( query(exists,A,true), ( A, ipl(B,x) ; \+A, iP(A,X) ) }.
ipl(A,x) +query(exists,A,true), ( A -- break{ipl(A,x)) ; ip(A,X) ) .
+-
P rogram 8:
58
I ?- ip(isort([3,2 ,1],[1,2,3]),X) .
query: isort( [2,II,x)? y.
which X? [1 ,2}.
query: isort( [II,x)? y.
which X? [I}.
query: isort( O ,X)? y.
which X? [I.
query: insert( 1 , [],[1 D? y.
x = insert(l,[j, [lJ)
and see that it needs 4 queries to detect the uncovered goal, compared
to 6 queries needed by the previous program.
Theorem 3.8 bounds the length and depth of computations of ip
as a function of the depth and length of computations of the faulty
computation. A similar argument shows that the running time of ip is
also bounded by the square of the running time of the faulty
computation: the number of iterations of ip is bounded by the depth
of the original, faulty computation, and the running time of each
iteration is bounded by that of the original computation.
59
Lemma 3.9:
Proof:
q8orl([1,2,1 ,3),Y8)
qBorl([1,1],Y8)
q8ort([l,1] ,Y8)
q8orl([l,1],YB)
However, the problem does not lie in
the
61
partition, since it may return an output list longer than its input list,
as in
I ?- partition( [ 1 1 ,1 ,xs,Ys) .
Xs = [1,11 ,
Ys = . 1]
If we examine the code for partition (or diagnose
partition( [I] ,I ,[I ,I],[]) using Ip) we find that the base clause is wrong,
and should be partition( O ,X,O ,[]). Hence the following definition.
Definition 3.10: Let M be an interpretation and >- a well
founded ordering on procedure calls. A procedure p is said
to diverge with respect to >- and M if it has a triple
<p,x,y> with a top level trace S for which:
62
63
Algorithm 4:
64
801ve(true,D,true)
!.
!.
8o1ve(A,O,( over/low,n))
801ve((A,B),D,S)
!,
801ve(A,D,Sa ),
( Sa=true - 801ve(B,D,Sb), S Sb ; S Sa ).
8olve(A,D,Sa) +8Y8tem(A) - A, Sa=true ;
Dl i8 D- l ,
clau8e(A,B), 8olve(B,Dl ,Sb),
( Sb=true - Sa=true ;
Sb=(over/low,S) - Sa=(over/low, [AISJ) ).
+-
+-
+-
Program 9:
A depth-bounded interpreter
1-
65
Sb=(overflow,S}
-+
Sa=(overflow,[(A+-B)ISJ).
It implements
stack overfloui,.P,S) +writel( [ ' error: stack overflow on ' ,P, '. diagnosing ']), nl,
(find _ loop(S,Sloop)
check _ segment(Sloop) ;
check _ segment(S) ) .
.
-+
P rogram 10:
The way solve and stack_ overflow are hooked together is application
dependent, and will vary between the different systems that use them.
We show here part of a session with the diagnosis system, described in
the next section, which uses these programs to diagnose the looping
66
insertion sort.
3 . 5 A diagnosis system
67
Program
11:
A diagnosis system
pds +nl, read( ' @ ' ,P), ( P exit ; solve and check(p), pds )
-
confirm solutions(P,[(Pl,x)ISJ) +
writel( [ ,solution: ',Pl, ' ; ']),
( ( system(Pl) ; fact(Pl,true) ) -+ nl, confirm solutions(P,S) ;
confirm( ' ok ' ) -+ assert _fact(Pl , true), confirm solutions(P,S) ;
assert _ fact(Pl,Ja/se) , false solution(Pl) )
confirm solutions(P, 1J) +wri te( ' no (more) solutions. ) ,
( system(P) -+ n l ;
confirm( ' ok ') -+ true ;
ask _for _ solution(p), assert _ fact(P,true), missing solution(p) ).
_
'
68
it ou t .
1 1- pds.
@ [ user}.
qsort( (xIL) ,LO) partition(L,x,Ll ,L2),
qsort(Ll,L3) , cp>rt(L2,L4 ) ,
append((XIL3),L4,LO).
partition((xIL},Y,Ll ,(xIL 2]) - partition(L,Y,Ll,L2).
partition ( [xIL),Y,[XiLl),L2) - X S Y, p artition(L,Y,Ll,L2 ).
p arti tion m ,x, (X} , D )
1.38 sec.
@qsort([ 2 , 1 ,3),X).
error: stack overflow on qsort( [2, 1 ,3) ,x). diagnosing
qsort([2],X) is looping.
69
+-
+-
+-
@qsort([2, 1 ,3],X).
no ( more) solutions. ok? n.
query: qsort{[2,1 ,3] ,x)? S .
which X? [1 ,2,3].
error: missing solution qsort{ [2, 1 ,3] ,[1 ,2,3j). diagnosing...
This
time the computation finitely failed; we tell the system that this
is incorrect behavior, and supply the desired output.
The
mi88ing solution program is then invoked.
70
which
X?
[I].
y.
y.
query: qsort([3],X)? y.
which X? [3].
query: append( [2 I ] , [3] , [ I , 2 3] )? n.
,
71
I qso;t ( [XIL],LO)
I
partition(L,X,Ll ,L2),
qsort(Ll ,L3), qsort(L2,lA),
I
append(L3, [X1 lA] ,LO).
I
+-
This time qsort returned a wrong solution; the system knowns that
qsort is determinate, and knows that qsort( [2,1 ,3],[1 ,2,3] ) is correct,
hence it could deduce that [2,1 ,3] is an incorrect output, and
automatically invokes the appropriate diagnosis algorithms.
+-
+-
+-
72
+-
+-
+-
This time the program finitely fails, and the error is found to be in
partition again. We examine the uncovered atom, and realize that
the first clause is supposed to cover it; it fails because we reversed the
arguments to the < test we just introduced.
I partition([XlL],Y,L1 ,[XlL2])
+-
X>Y, partition(L,Y,L1,L2).
So we fix it.
@qsort([2, 1 ,3],X).
solution: qsort([2,1 ,3],[1,2,3]);
no (more) solutions. ok? y.
@qsort( [2, 1 ,4 ,3, 66 ,2, 477 , 4] ,x) .
solution: qsort([2, 1 ,4 ,3, 66 ,2, 477 , 4] , [ 1,2,2,3, 4 , 4 , 66 , 477] ); ok? y.
no ( more) solutions. ok? y.
@exit.
This time qsort behaves to our satisfaction, so we end the
diagnosis session, and return to top-level Prolog .
73
74
3.6. 1 Negation
Jp(not(A),X)
ip(not(A),X)
+-
+-
iP(A,X).
JP(A,X).
A goal not(A) s ucc eeds iff A finitely fails; hence if the goal
not(A) erroneously succeeded, is means that A erroneously finitely
faile d . This justifies the clause /p(not(A),X) +- ip(A,X). Similarly, if
not(A) erroneously failed, it follows that A erroneously succeeded;
hence the clause ip(not(A),X) +- /P(A,X) is correct. The augmented
ip and Jp can return now either an instance of a clause or a goal; in
the former, the clause is a false instance of a clause in P, in the latter
the go al is a true goal uncovered by P in M.
We demonstrate the behavior of /p and ip, augmented with
these two clauses. The version of /p used is the one in Program 4,
and of ip is Program 7. The more sophisticated implementations of
Jp and ip in Programs 6 and 8 need more elaborate modifications to
handle negation.
Consider the fo llowing program that finds an element in the
symmetric difference of two lists.
dil/erence(X,Ys,Zs)
dil/erence(X,Ys,Zs)
++-
member(X,Ys), not(member(X,Zs)).
member(X,Zs), not(member(X,Ys)).
member(X, [Y\Xs]).
member(X, [Y\Ys]) +- member(X,Ys).
We try it on a simple example:
75
n.
no
and get the correct result.
3.6.2 Control predicates
76
77
78
--+
--+
P rogram 12: An
79
-+
ordered(Y)
is readable, easy to verify, and may save the user from answering
some queries if it is known by the system. It is easy to incorporate
constraints and partial specifications in the current scheme, by making
the query procedure first consult the available information about the
intended input /output behavior of the program, and ask the user only
if it fails to answer the query using this information.
We found two other types of information useful: whether a
procedure is determinate, i.e. whether it has at most one solution to
any goal in a given domain, and whether it is total, i.e. has at least
one solution for any goal in a domain. If a procedure has two
solutions for a determinate goal, the diagnosis system can conclude
that at least one of them is false, and after performing at most one
query can invoke false solution. If a procedure is total, then the
interpreter can trap termination with missing output as soon as it
occurs in such a procedure, and apply missing_ solution starting at
this point in the computation.
The following two clauses, added to the result procedure in
80
Program
12
Chapter 4
INDUCTIVE PROGRAM SYNTHESIS
82
83
84
n'
85
86
Definition
4.1 :
87
88
89
90
91
Algorithm 5:
Algorithm:
set P to be the empty program.
let the set of marked clauses be empty.
repeat
read the next fact.
repeat
if the program P fails on a goal known to be true
then find a true goal A uncovered by P using Algorithm 3;
search for an unmarked clause p in L that covers A in X;
add p to P.
if the program P succeeds on a goal known to be false
then detect a false clause p in P using Algorithm 2;
remove p from P and mark it.
until the program P is totally correct
with respect to the known facts.
output P.
until no facts left to read.
if the depth of a computation of P on some goal A exceeds h ( A) ,
92
A presentation S of an interpretation M
for a language L is an infinite sequence of facts about M
such that for any variable-free goal A in the Herbrand base
of L, if A is true in M then <A,true> is in S, otherwise
<A,faise> is in S.
Definition 4.2:
M.
93
Theorem 4.4:
Assume that Algorithm 5, applied to a
presentation of an interpretation M, eventually reads in
every fact, and converges to some program P. Then P is
totally correct in M.
94
Proof:
Lemma 4.8:
95
Proof:
1.
96
4.9:
Theorem 4.10:
97
98
99
Program
13:
100
101
The system found a clause that covers the facts. The clause for
concat(X,Y,Z) returns in Z the value of Y with X inserted in its second
position. The clause is correct for input lists of length one only. We
give it a more complex example.
Next fact? concat(a,[c,b1,[c,b,a]),true.
Checking fact(8)
Error: mi88ing 80lution concat(a,[c,bl , [c,b,a)). diagn08ing...
Error diagn08ed: concat(a,[c,b] ,[c,b,aJ) i8 uncovered.
..
X = [c,b,aJ
102
[11 no
I? - tz
[ EndBreak (level 1) I
We found that the program is still incorrect,
with the appropriate fact.
so
A counterexample to the base clause was. found, and the clause was
removed.
Checking Jact(s)
Error: missing solution concat(a, [ bl , [b,a]). diagnosing
Query: concat(a,[],[a])? y.
Error diagnosed: concat(a,[], [aJ) i8 uncovered.
After the wrong base clause is removed, the program failed on one of
the examples; the diagnosis algorithm was applied, and diagnosed the
error: a base clause for con cat is missing.
Searching Jor a cover to concat(a,[] , [a])
Checking: ( concat(X,Y,[Xll1)+-true)
Found clau8e: (concat(X,Y,[Xll1)+-true)
aJter 8earching 7 clau8e8.
Listing of concat(X,Y,Z):
(concat(X, [Y1z],[Y1V])+-concat(X,Z, V) .
( concat(X,Y, [Xll1)+-true).
Checking Jact(s)
103
104
105
..
106
The next fact we supplied caused the system to discard that false
clause.
Checking fact( s ) ..
Error: missing solution member( a,[b,aj). diagnosing
Error diagnosed: member(a,[b,a]) is uncovered.
.
..
Query: member(a,[a])? y.
Query: member(b,[a])? n.
These two queries were performed by the eager search algorithm. The
first
was
used
to
determine
whether
the
clause
member(X, [l1Z])member(X,Z) covers member( a, [b,aj), and the
answer is positive; the second was to determine whether
member(X,[l1Z])member(Y,Z) covers it, and the answer is negative.
107
The reason for this search order will be clarified when the pruning
strategy is discussed, in Section 4.5 below.
Checking: (member(X, [Y,Z! U] )-true)
Refuted: (member( a, [b,cD-true)
Checking: (member(X, [y\2]) - member{X,Z))
Founi' clause: (member(X,[y\2]) - member(X,Z))
after searching 4 clauses.
Listing of member{X,Y):
(member(X, [y\2])-member(X,Z)).
The algorithm found the recursive clause for member, even though no
instance of it w as supplied by the user initially. The clause covers
member(a, [b,a]), but cannot solve it, since a base clause for member is
missin g.
Checking fact(s) ...
Error: missing solution member(a,[b,a]). diagnosing
..
Query: member(a,[])? n.
Error diagnosed: member(a,[a)) is uncovered.
The fact < member(a, [a]), true> is known by the system; this saved
the user from answering this query to the missing_ solution diagnosis
program.
Searching for a cover to member(a,[a))
Checking: (member(X, [y\2])-true)
Refuted: (member(a,[b,c] )-true)
Checking: (member(X, [l1)-true)
Refuted: (member(b,[aD-true)
Checking: (member(X,[XI 2]) - true)
Found clause: (member(X,[X!2])-true)
after searching 4 clauses.
Listing of member(X,Y):
(member(X, [y\2])-member(X,Z)).
..
108
( member(X,[XIZ])+-true).
Checking fact(s) no error found.
Proof:
109
or a
covers( eager,(P+-Q),Pi)
verily(( P Pl , satisfiable(Q) )).
+-
satisliable((P,Q))
!,
query( exists,p,true), satisfiable( Q).
satisfiable(p) +query( exists,p,true).
+-
Program 14:
1 10
111
Checking fact(s)
Error: missing solution member(b, [a,b] ). diagnosing
Error diagnosed: member(b,[a,b]) is uncovered.
. .
..
..
The new clause found by the system says that X is a member of any
list of which X is the second element. Here the difference between the
eager and lazy search strategies becomes apparent: although the
clause
member(X, [l1Z])+-member(X,Z)
precedes
member(X, [y,xI U])+-true in the enumeration, the search algorithm
did not suggest it when searching for a cover to member(b,[a,b] ) since
it does not know that member(b,[b] ) is true. Continuing with this
ordering of facts, we can force the algorithm to augment the program
with arbitrarily complex base cases ( unit clauses) , that say "X is a
member of Y if X is the nth element of Y' , for larger and larger n's.
Instead, we provide it with a fact for which it can find a recursive
rule.
1 12
..
The system found the recursive clause for member when searching for
a cover to member{b,[x,a,bD. The lazy cover8 test succeeded since the
system knew from previous facts that member{b,[a,b] ) is true.
Even though we can force the member program constructed by
the system to be arbitrarily complex, it will still identify member in
the limit, since eventually we would have to supply it with the facts it
needs for finding a recursive rule. This is not always the case,
however; the following example shows that adversary orderings of
facts m ay prevent identification in the limit by Algorithm 5 with a
lazy search strategy, even though eager search strategy would allow
identification.
Assume that L contains the following clauses, constructed from
the predicate symbols p and q, the one place functions a and b, and
the constant nil.
1 13
interpretation is
p( a(X))
q(X).
q(b(b(X) ))
q(X).
q( nil).
+-
+-
1 14
Lm'
1 15
---+
Program 15:
116
member(a,[aj), true.
member(b,[a,b]), true.
"member(a,[x]), false.
member(b,[a,xj), false.
it came up with the program
Checking fact(s)
Error: missing solution member(b, [a,b] ). diagnosing
Error diagnosed: member(b,[a,b) ) is uncovered.
117
1 18
Program 1 6 :
4 . 5 A pruning strategy
1 19
that PI=P, pn =q, and PHI is in P(Pi)' for O i< n. We say that
p q iff p< q or p=q. Note that we do not distinguish between
clatses that ':tre variants, i.e. differ only in the choice of variable
names, and interpret p=q accordingly.
The mapping P is said to be a refinement operator over L iff the
following two conditions hold:
1. P =D and q=a(XI ,x2 ' ... 'Xn ), for some n-place predicate
1 20
subset( U ,X)
121
+-
m ember(X,Ys), subset(Xs,Ys).
append( [] ,X,X)
append( [A I X] ,Y,[A I Zl) +- append(X, Y,z)
isomorphic(X,X).
isomorphic(t(Xl ,X2),t(Yl ,1'2))
isomorphic(Xl ,Yl), isomorphic(X2,1'2).
isomorphic(t(Xl,X2),t(Yl ,1'2))
isomorphic(Xl , 1'2), isomorphic(X2,Yl).
+
mem Y)
--
member(X,[xIZJ)
Figure 6:
member(X,[yIZ-membeZ)
122
8 ==>
1 23
is in N and t is in
T.
1 24
And by adding to its third clause the restriction that the goal is added
to the body of the clause only if it has less than k goals in it.
Let G be a context-free grammar. We say that grammar rule R
generates s in G if there is a derivation of s in G that starts with R.
L et M be an interpretation that corresponds to the language
generated by G. From the correspondence between context-free
grammars and definite clause grammars it follows that a definite
grammar clause p covers a goal n(X,Y) in M iff the grammar rule
that corresponds to p generates the string that is the difference
between X and Y in G. Hence we argue about the size of the
candidate space in terms of grammar rules.
Lemma 4. 17:
'
1 25
This grammar contains two errors: the rule for a procedure call is
overgeneralized, as PLO has only parameterless procedure calls, and
the rule for statementlist is too constrained, as it implies that a
statement list has only one statement. From this point the session
continued as follows. We first gave the system two additional facts:
was
as
so
the timing
126
And corrected the two errors ( in 20 CPU seconds) . The new grammar
rules are:
(5) statement( [calllX] ,Y):-ident(X,Y)
(9) statementlist( [;IX] ,Y): - statement(X,U),8tatementii8t(U, Y)
The final grammar is:
1 27
1 28
Algorithm 6:
PH I
covers A, a
1 29
search " lor cover(P,Cj <4nl, writel( [ ' Searching lor a cover to ' ,P, ' ' ]), nl,
mgt(P,Pl ),
search _ lor cover( [(Pl<4-true) IXs] ,Xs,P,Cj.
-
'
'.
<4-
<4-
covers(X,
X covers P. See Programs for the covers test, Section 4.4.
<4-
1 30
pack( [Xl l1 , z)
pack([] ,[]).
+-
pack(Y,V) ,append( X, v, Z) .
1 1- m is.
Next fact? pack([] , O),true.
Ch ecking fact( s ) . .
Error: missing s olution pack([] , []). diagnosing...
.
131
+-
After searching for not too long, the system found a program that is
consistent with all it knows so far: on any input, pack would return
now the empty list.
The clause found would return the first element of any nonempty list.
132
1 33
Checking fact(s}
Error: missing solution pack([[a] , [b]],[a,b] } . diagnosing
Error diagnosed: pack( [[a] ,[b]] , [a,b]} i8 uncovered.
Checking fact(8} .. .
Error: wrong 80lution pack( [[a],[b] ,[c]] ,[a, b) ) diagn08ing
The first error was detected by executing the new program against the
known facts, and was diagnosed using one user query. The same is
true for the following error.
Checking fact(8)
Error: wrong solution pack( [[a) , [b) , [c]],[a,b)). diagno.8 ing
true} i8 false.
134
Listing of pack(X,Y):
(pac k( [XIYJ , z)
pack(Y,V),append(X, V, Z) ).
+-
Checking fact(s)
Error: missing solution pack([] , [] ). diagnosing...
Error diagnosed: pack( [],[] ) is uncovered.
+-
1 35
+-
1 36
s( [a l x] ,x)
s( [- I x] , y)
s(X,Y).
s( [a,+ I x] ,y)
s(X,Y).
s([a l x] , y)
s(X,Y) .
s( [( Ix] , y)
s(X, D l l1)
We added three negative facts:
+-
+-
+-
+-
s( [a,aj, [] ), false.
s([-,-,a], O), false.
s( [,a, aj , []), false.
And the system came up with the program:
s([a l x] ,x)
s([a, + Ix] ,y)
s(X,Y).
8([ ' ( ' I X] ,Y)
8(X,[ ' ) , 1 11)
8( [a,-I x] ,y)
8(X,Y).
8( [-,a l x] ,x)
true.
8([-1 x] , y)
s(X, [+I u) ),s(U,y).
8( [-, '( ' I X] Y)
8(X, [ ' ) , 1 11)
s([- Ix] , y)
s(X,[- I u) ),s(U, y) .
+-
+-
+-
+-
+,
+-
+-
S :=!;
S :=!;
S :=!;
S :=!;
S :=!;
S :=!;
S :=!;
S :=!;
a
a + S.
( S ).
a
S.
-
a.
- S + S.
- ( S ).
- S S.
-
1 37
Chapter 5
PROGRAM DEBUGGING
139
at the program level, but not at the clause level. Our approach to
debuging attempts to correct this drawback. To do so we follow the
Program Mutation Project [18], and make the competent programmer
assumption. We assume that the initial program was written with
the intention of being correct, and that if it is not correct, then a close
variant of it is. The debugging algorithm we develop tries to find
such a variant; if it fails, it depends on the programmer to make the
necessary change.
Formally, we make two assumptions. The first one, common in
the field of program testing ( e.g. [16, 47, 105]), is that the class of
common errors we try to correct induces an equivalence relation on
the set of candidate clauses. For example, the following two clauses
append([XIXs],Ys,[Z1Zs])
append([XIXs],Ys,[X!Zs])
+-
+-
append(Xs,Ys,Zs)
append(Xs,Ys,Zs)
Detinition
5.1:
140
+-
append(Xs,Ys,Zs}
14 1
Algorithm 7:
Interactive debugging
142
143
Definition 5.2:
Definition 5.3:
Lemma 5.4:
Pv
= ,
Pt
144
145
Proot:
146
Algorithm
8: A bug-correction algorithm
147
148
I
declare(append(+[x],+[x],-[x)),[determinate,total)).
I
I
declare _called(append(X, Y,Z),[append(_, _, _)]).
I
I tz
+-
+-
1.00 sec.
+-
partition(Y,Z,U,liI))
149
after searching
ok? n.
clauses.
Query: qsort([],X)? y.
Which X? [I.
Error diagnosed: qsort(O,[]) is uncovered.
add (y) or (m)odify a clause? y.
which? qsort([],O).
Listing of qsort(X,Y):
(qsort([Xly),z) partition(Y,X,W,x1),qsort(W,ZI ),qsort(XI,VI),
append(ZI, [XI VI],Z)).
(qsort([],O) - true).
150
The second error the system finds is easy to correct: the base clause
for qsort is missing, so we add it manually. The algorithm tries to
solve the original goal again.
Solving qsort([2,1,31,x)
Error: stack overllow on qsort([2,1,31,x). diagnosing
append([1],[2,3],X) is looping.
Error diagnosed:
(append([11,[2,31,x)
append([11,[2,31,[11X])) is diverging.
..
+-
This time a stack overflow occurred; the error was diagnosed with no
user intervention, since the stack overflow diagnosis algorithm found
two duplicate goals on the stack. We request the system to modify
the diverging clause. The system, in turn, prompted us for a reason
fOT that clause, so it would know how to modify it.
retract (y), (m)odily, or (r)eplace it? m.
lVhat is a reason lor (append([Xll1,Z,U)
append([Xll1,Z,[Xlu]))?
append ( [1,21,[3,4],[1,2,3,4]).
Derelining (append([Xll1,Z,U) +- append([Xll1,Z,[X I u] ))
Relining: (append([Xll1,Z,u) +- true)
+
151
Query: append([2],[3,4],[2,3,4])? y.
Found clause: (append([XIy],Z,[Xll1)
append(Y,Z,V
alter searching 85 clauses.
ok? y.
Listing 0/ append(X,Y,z):
true).
(appendm,X,x)
(append([Xly],Z,[X1l1)
append(Y,Z,V.
+-
+-
+-
Since the system uses eager search strategy ( see Section 4.4) we had to
answer a few queries during the search process, but eventually a
correct recursive definition of append was found. The system tries the
original goal again.
Solving qsort([2,1,31,x)
solution: qsort([2,1,3],[1,2,3]); ok? y.
no (more) solutions. ok? y.
@qsort (12,1,4,3],x).
Solving qsort([2,1,4,3],x)
solution: qsort([2,1,4 ,3],[1,2,3,4]); ok? y.
no (more) solutions. ok? y.
.
152
Query: qsort([1,2],[l,2])? y.
Query: qsort([3],[3])? y.
Query: append([l,2],[ 2,3],[l,2,2,3])? y.
Query: partition([l,2,3],2,[l,2],[3])? n.
Query: partition([2,3],2,[2],[3])? n.
Error diagnosed:
(partition([2,3],2,[2],[3]) - partition([3],2,O,[3]),22) is lalse.
retract (y), (m)odily, or (r)eplace it? m.
What is a reason lor
(partition([XIYJ,Z,[Xll1,lt) - partition(Y,Z,v,lt),xZ)?
partition([l],2,[l],0).
Relining:
(partition([XIYJ,Z,[Xll1,lt) - partition(Y,Z,v,lt),XZ)
Found clause:
(partition([XlYJ,Z,[Xll1, It) - partition(Y,Z,V, It),xZ,X<2)
alter searching 2 clauses.
ok? y.
Listing 01 partition(X,Y,Z,U):
(partition(O,X,O,o) - true).
(partition([XlYJ,Z,U,[X I "1) - partition(Y,Z,U,It),Z<X).
partition(y,Z,v,lt),xZ,X<2).
(partition([XlYJ,Z,[Xll1,It)
-
The system found that the test in the false clause was too weak, and
it strengthens to <; however, since it has no built in knowledge
about the semantics of and <, it cannot conclude that once the <
test is added, the test becomes superfluous. It is conceivable that a
post-processing stage can be added in which such an optimization can
be incorporated.
Solving qsort([2,1,2,3],X)
Error trapped: no 80lution to partition([2,3],2,X,l')
Error: missing solution partition([2,3],2,X,l'). diagn08ing
153
Query: partition([2,3],2,X,y)? y.
Which (X,Y)? [],(3].
Error diagnosed: partition([2,3],2,[],[3]) is uncovered.
add (y) or (m)odify a clause? m.
which? any.
The original partition program had no special clause for the case
where the first element on the partitioned list and the partitioning
element are equal. So we send the search algorithm off to look for
such a clause.
Refining: (partition(X,Y,Z,U) - true)
Checking: (partition([Xll1,Z,[],y) - true)
Refuted: (partition([3],2,[],[]) - true)
Found clause: (partition([Xll1,Z,U,V) - partition(Y,Z,U,V))
after searching 39 clauses.
ok? y.
Listing of partition(X,Y,Z,U):
(partition([],X,[],[]) - true).
(partition( [Xll1,z,U,[XI"1) - partition(Y,Z,U,"1,Z<x).
(partition([Xll1,Z,[Xll1,"1- partition(Y,Z,v,"1,X::;Z,X<z).
(partition([Xll1,Z,U,v) - partition(Y,Z,U,V)).
Error: wrong solution partition([3],2,[],[]). diagnosing...
Error diagnosed:
(partition([3],2,[],[]) - partition([],2,[],[])) is false.
154
+-
+-
+-
+-
Solving qsort([2,1,2,3],X)
Error trapped: too many solutions to partition([1,2,3],2,X,y)
.
Query: partition([l,2,3],2,[],[3])? n.
Error: wrong solution partition([1,2,3],2,D,[3]). diagnosing...
Error diagnosed:
(partition([1,2,3],2,D,[3]) +- partition([2,3],2,D,[3]),12) is false.
retract (y), (m)odify, or (r)eplace it? m.
lVhat is a reason for
(partition([XIy),Z,u,V)
partition(Y,Z,U,V),xZ)?
partition ( [2],2,[],[]).
Refining: (partition([XIy),Z,U,V)
partition(Y,Z,U,V),x <Z)
Found clause:
(partition([XIy),Z,U,V)+-partition(Y,Z,U,V),X Z,ZX)
after searching 2 clauses.
ok? y.
+-
+-
155
Listing of partition(X,Y,Z,U):
(partition([],X,[],O)
true).
(partition([X1l1,Z,U,[XI"1) +- partition(Y,Z,U,liI),z<X).
(partition([X1l1,Z,[Xll1,l'\1 +- partition(Y,Z,v,liI),xz,x<Z).
(partition([Xll1,Z,U,V) +- partition(Y,Z,U, V),xZ,ZX).
+-
Solving qsort([2,1,2,3],X)...
solution: qsort([2,1,2,3],[1,2,3j)i ok? y.
no (more) solutions. ok? y.
append(O,X,X).
append([Xll1,Z,[X1l1)
+-
append(Y,Z, V).
156
Chapter 6
CONCLUSIONS
Since the
and
attempts
to
draw
from
them
implications
158
Because of the theoretical nature of this work, and the fact that
it evolved mostly in the context of inductive inference, I have not
implemented the debugging algorithms for full Prolog, and as a
consequences did not use them extensively in real programming tasks.
However, I have reasons to think that it is valid to extrapolate from
the sterile environment of inductive inference to the world of real
debugging.
for finite failure, I have been using its underlying mechanism within
the standard Prolog debugger.
The
divide-and-query
algorithm
can
I found the
good diagnosis
not
be
easily
wants to do is inspect the stack to see what's going on. The diagnosis
algorithm enables the programmer to do so, but in a structured way,
focusing his attention on the suspicious component of the stack, i.e.,
the part of the stack that contains a duplicate procedure call.
A simple implementation of the first two diagnosis algorithms is
available in micro-Prolog
systems
and
investigated
their
[62];
adaptation
to
Pascal
is
also
being
[79, 80].
enough
to
be
analyzed
theoretically,
and
is
amenable
to
an
159
that
it
is
incremental,
which
enables
gradual,
evolutionary
If an axiom is discovered
invaluable
role in
Prolog
achieving
these results.
appreciate this fact I describe the way this research has developed.
The original problem I was concerned with was that of scientific
discovery:
in scientific progress
[77, 78],
[88, 89],
which formalizes
[13].
[39]
and the
160
The next logical step was to implement the algorithm and test it.
Although I did not know Prolog at the time, rumors suggested that it
would be the ideal implementation language.
Since I was the first and only Prolog user around, I had to
Programmers
used
to
share
programming
tricks
and
algorithm
was
after
restricted
version
of
the
the
The
( which
was natural to
Drew McDermott, not to me) was to add to the theory only axioms
that are truly useful in the derivation.
The diagnosis
structure
of
the
target
programs.
However,
when
[13]:
16 1
[901,
program,
and
would
not
terminate
thereafter.
This
"theoretical bug" in the Model Inference System was not fixed until
the development of the algorithm that diagnosed stack overflow, and
the incarnation of the Model Inference System described in the thesis
is the first to be correct in this sense.
These examples show that attempts to implement a theory can
lead to its enhancement and development.
the case:
assembly language I might have succeeded, but the theory would have
remained intact. Due to the nature of Prolog, the problems I faced in
the implementation were interesting and abstract enough to stimulate
further theoretical research, and to make results of this research
relevant to their solution.
Prolog helped extend the theory in another way, by allowing
easy experimentation with different ideas.
search strategies described in Section
4.4
for
the
Inference System:
more
interesting
applications
of
the
Model
4.4),
Page
196).
162
importance
of
implementation
in
the
development
of
theories has been the bread and butter of Artificial Intelligence since
its beginnings, and the need for a high level language in such an
endeavor was also recognized.
all
successful
sciences
search
for
the
simplest
to determine if
it
is
simple
or messy.
think
I have
debugging can
research
model
[63],
tool.
but
partly
Lisp
due
originated
to
in
clean
computational
the inexpressiveness of
the
pure
Lisp
implementations
and
programming styles
are
only
163
[96]:
to it
"Lisp... is like a ball of mud. You can add any amount of mud
and it still looks like a ball of mud!". This aspect of Lisp is the
..
It is
known that one may implement without too much effort a reasonable
Prolog in Lisp.
my
approach
and
[83]
the
approach
of
MIT's
as
the complexity of the formalism they need in order to explain even the
simplest program seems forbidding
[82].
result I
no
3.6.
analytic
argument
can
irrevocably
resolve
(perhaps
164
and
algorithms,
the
in
environments
light
[87].
implementation
of
language
Sandewall's
Sandewall
lists
of
discussion
the
the
on
following
debugging
programming
properties
[programming environment]
the
programming
system
should
be
to
read
an
expression from the user, execute it, and print out the
results while preserving global side effects to its database.
The expression itself may of course contain such things as
procedure calls.
Procedure oriented.
as
easy as
so
happens
that
these
are
exactly
the
properties
However, I claim
that Prolog scores on all these issues just as well as Lisp does, and on
the most important of them - bootstrapping - even better.
shown in the Prolog introduction ( Program
3,
Page
30),
As
pure Prolog
165
interpreter written in pure Prolog is just three simple clauses. All our
diagnosis algorithms are augmented interpreters, hence the ease of
implementing and experimenting with them correlates directly with
the ease of implementing and augmenting an interpreter for the
language within the language.
However, one important property is missing from Sandewall's
list:
If
natural way.
One
conclusion
from
this
argument
is
that
kitchen-sink
languages such as Ada will lose in the long run, since the effort
required to create a programming environment that understands all
their features will be insurmountable.
mise
,_
,_ ,_
167
Query: insert(2,[1,3],[1,2,3))? y.
Found claU8e: (isort([XIJ1,Z)-isorl(Y,V),insert(X,Y,Z)
after searching 61 clause8.
Listing of isort(X,Y):
(i80rt([XI 11 ,Z)-isort(Y,V),in8ert(X,Y,Z).
After searching through 61 clauses, the system round a clause
that covers isort([2,3,lj,[1,2,3]), which happens to be also the right
recursive definition or insertion sort. It round the necessary racts to
determine the coverage by querying the user, as it uses eager search
strat egy. An unpruned breadth-first search through this refinement
graph would have gone through 165 clauses berore finding this clause.
The unpruned search space is already restricted by the type and mode
declarations.
Query: isort([lj,X)? y.
Which X? [I].
Query: isort(U,X)? y.
Which X? U.
Error diagnosed: isort(U,U) is uncovered.
And the system round that the base case ror isort is missing; the racts
known already by the system saved two queries ror the diagnosis
algorithm: isort([2,3,1],X), and i80rt([3,11'x).
168
Checking fact(s)
Error: missing solution isort([2,3,1},[1,2,3]). diagnosing
..
Query: insert(l,O,[I])? y.
Error diagnosed: insert(l,D,[I]) is uncovered.
Searching for a cover to insert(l,U,[l])
..
Declare insert(X,Y,Z)?
declare(insert ( +x,+[x],-[xD,[total,determinate))
Procedures called by insert(X,Y,Z)? insert(_,_,_ ) ,
Found clause: (insert(X,Y,[X1l1)true)
after searching 8 clauses.
Listing of insert(X,Y,Z):
(insert(X,Y,[Xll1)true).
.
_
The clause that was found is incorrect, but is consistent with the facts
we have supplied to the system so far.
Checking fact(s)
Error: missing solution isort([2,3,1],[1,2,3]). diagnosing...
..
Query: insert(3,[l],[1,3])? y.
Error diagnosed: insert(3,[1],[1,3]) is uncovered.
Searching for a cover to insert(3,[1],[1,3]) ...
Query: insert(3,U,[1,3])? n.
Query: insert(1,D,[1,3]) ? n.
169
system,
so
we
[2,3,1]
[1] yes
We find an error, so we tell the system about it.
I?- jZ
[ End Break (level I) ]
Next fact? isort([2,3,1],[2,3,1]),false.
Checking fact(s)...
Error: wrong solution isort([2,3,1],[2,3,1]). diagnosing
Query: insert(3,[I],[3,1])? n.
Error diagnosed: (insert(3,[I],[3,1])+-true) is false.
Listing of insert(X,Y,Z):
(insert(X,[ l1Z],[y,xIZ])+-true).
Checking fact(s)
Error: missing solution isort([2,3,1],[1,2,3]). diagnosing.
Error diagnosed: insert(I,O,[l]) is uncovered.
.
170
so
I?- isort([2,3,1],X).
x
11,2,3] ;
II] no
I?- isort([2 1 31,X) .
,
[3,2,1]
11] yes
The program behaves correctly on the original input, but not on the
new input tried.
Query: isort([31,13])? y.
Query: isort([1,3],[3,1])? n.
Query: insert(I,13],[3,1])? n.
Error diagnosed: (insert(I,13],[3,1])+-true) is false.
171
Listing of insert(X,Y,Z):
(insert(X,[ J,[X])+-true).
Checking fact(s}...
Error: missing solution isort([2,3,1],[1,2,3]). diagnosing...
Error diagnosed: insert(3,[I],[1,3]) is uncovered.
Searching for a cover to insert(3,[I],[1,3])
Query: insert(3,D,[3])?
..
y.
Query: insert(I,D,[3])? n.
Found clause: (insert(X,[Y12],[Y,XI2])+-yX)
after searching 45 clauses.
Listing of insert(X,Y,Z):
(insert(X,[J, [X])+-true).
(insert(X,[Y12],[Y,xj2])+-YX).
Checking fact(s}... no error found.
Next fact? break.
[Break (level I} ]
I?- isort([2,1,3],X).
[I] no
I? - fZ
[ End Break (level I} ]
Next fact? isort([2,1,3j,[1,2,3]),true.
Checking fact(s}
Error: missing solution isort([2,1,3j,[1,2,3]). diagnosing
..
Query: isort([1,3],X)? y.
lVhich X? [1,3].
172
Query: isort([3],X)? y.
Which X? [3].
Query: insert(I,[3],[1,3])? y.
Error diagnosed: insert(I,[3],[1,3]) is uncovered.
Searching for a cover to insert(I,[3],[1,3])
Found clause: (insert(X,[Y1z],[X,Y1 z])+-XY)
after searching 32 clauses.
Listing of insert(X,Y,Z):
(insert(X,[],[X])+-true).
(insert(X,[Y12],[Y,XIz])+-yX).
(insert(X,[Y1 2], [X,YJ2])+-X Y).
..
[1,2 ,3] ;
[I] no
I?- isort([3,2,lj,X).
X
[1,3,2]
[I] yes
and find an error, which we inform the system via the following fact.
173
Query: isort([2,1],[1,2])? y.
Query: insert(3,[1,2],[1,3,2])? n.
Error diagnosed: (insert(3,[1,2],[1,3,2])-13) is false.
Listing of insert(X,Y,Z):
(insert(X, 0, [X])-true).
(insert(X,[Y]Z],[X,Y]Z])-XY).
Checking fact(s) ...
Error: missing solution isort([2,3,lj,[1,2,3]). diagnosing
Error diagnosed: insert(3,[lj,[1,3]) is uncovered.
Searching for a cover
to
insert(3,[lj,[1,3]) ...
Query: insert(3,D,[])? n.
Query: insert(l,D,IJ)? n.
Found clause: (insert(X,[YJZ],[YJV1)-insert(X,Z,V),YX)
after searching 51 clauses.
Listing of insert(X,Y,Z):
(insert(X,O,[X])-true).
(insert(X,[Y]Z],[X,Y]Z])-XY).
(insert(X,[l1z],[l1V1)-insert(X,Z,V),YX).
Checking fact(s) no error found.
..
isort([2,3,lj,[1,2,3]), true.
isort([2,3,lj,[2,3,1]), false.
isort([2,1,3j,[3,2,1]), false.
isort([2,1,3j,[1,2,3]), true.
isort([3,2,lj,[1,3,2]), false.
13 facts were queried by the search algorithm:
174
and
1.2 Inferring
In this
context-free grammar
sess i on
for
subset of Pascal.
175
terminal{X}
member{X,
[begin, end, if, then, while, do, call, ':=', ';',
( , ) , +, - ,* ,I, <, =]).
nonterminal{N}
member(N,[
statement(X,y), statementlist(X,y), condition(X,y),
expression(X,y), term(X,y), factor(X,y), ident(X,Y),
number(X,Y), comparator(X,y),
plusminus(X,Y), timesdiv(X,Y) D.
+-
'
'
'
'
+-
I ?- mis.
Next fact? factor([a], []),true.
Checking fact(s}
Error: missing solution factor([a],D). diagnosing...
Error diagnosed: factor([a],[]) is uncovered.
.
171)
Listing of factor(X,Y):
(factor(X,Y)+-ident(X,Y)).
Checking fact(s) no error found.
..
177
Query: factor([a,*,b),U)? n.
Error diagnosed: term([a, *,b),[]) is uncovered.
Searching for a cover to term([a, *,b],[])
Checking: (term(X,Y)-factor(X,U),timesdiv(U,lt),term(W,Y))
Found clause:
(term(X,Y)-factor(X,U),timesdiv(U,It),term(w,Y))
after searching 20 clauses.
Listing of term(X,Y):
(term(X,Y)-factor(X,Y)).
(term(X,Y)-factor(X,U),timesdiv( U,It),term{w,Y)).
.
178
Query: term([a],X)? y.
lVhich X? [].
lVhz'ch Xl n.
Nonterrninals in context-free grammars are not determinate
procedures, hence an existential query may have several different
solutions. We supply all solutions (in this case there is only one),
following by no.
Query: term([(,2,*,b,)],0}? y.
Query: factor([(,2, *,b,)),[J)? y.
179
Checking fact(s)...
Error: stack overflow on term([a,*,b],O). diagnosing
The following three of the grammar rules found by the system so far
expression(X,Y) term(X,Y).
factor(X,Y) +- ezpression(X,Y).
term(X,y) factor(X,Y).
+-
+-
term([a,*,b],[]) is looping.
Is (term([a,* ,b], IJ),factor([a,*,b],[])) a legal call? y.
Is (jactor([a,* ,b],[]),ezpression([a, *,b],O)) a legal call? n.
Error diagnosed:
(jactor([a,* ,b],[])+-expression([a, *,b],[]) is' diverging.
We have resolved the trilemma using the knowledge of the
hierarchical relationship between the three nonterminals, expression,
term, and factor, and the system responds accordingly.
Listing of factor(X,Y):
(/actor(X,Y)+-ident(X,Y)).
(/actor(X,Y)+-number(X,Y)).
180
(expression(X,Y)+-term(X,U),plusminus(U,,),term(w,Y)).
(expression(X,Y)+-term(X,Y)).
(term(X,Y)+-factor(X,y)).
(term(X,Y)+-factor(X,U),timesdit:{U,,),term(w,Y)).
(factor(X,Y)+-ident(X,Y)).
(factor(X,Y)+-number(X,Y)).
(factor([(Ix],y)+-expression(X,Dll1))
1 2 facts were needed to infer this grammar:
181
lact(factor([a],[]),true)
/act( /actor(fl],fl),true)
lact(term( [a],[]),true)
lact{expression([a,+,l],[]),true)
lact(term{[a,*,b],[D,true)
lact{expression([a], [J),true)
lact(term([a ],[]),true)
lact(expression([a,+,(,2, *,b,}],[]),true)
lact(term([a,+,(,2, *,b,)],[+,(,2, * ,b,)]),true)
lact(term([(,2, *,b,}],[]),true)
lact(factor([(,2, ,b,)],[]),true)
lact(factor([a,*,b],[]),lalse)
*
was
too general,
so
we gave it
182
statement([a,*,2,:=,aj,O),false.
statement([a,*,2,:=,aj,0),false.
statement([l, :=,aj,[]),/alse.
The system went through some wrong alleys, but finally came up with
the right rule:
(statement(X,Y)+-ident(X,[:=IU)),expre88ion(U,Y)).
From that point things became easier ; we then gave the system
the following facts :
183
it
came
up
with was:
(statement(X,Y)ident(X,[:=IU)),expression(U,Y)).
(statement([whilelX],Y)condition(X,IdolU)),statement(U,Y)).
(statement([iflX],Y)condition(X,[thenlU)),statement(U,Y)).
(statement([beginlX],Y)statementiist(X,[endll1)).
(statementlist(X,Y)statement(X,[;IU)),statement(U,Y)).
( condition(X,Y)
expression(X,U),comparator(U,lV),expression(W,Y)).
(expression(X,Y)term(X,U),piusminus(U,lV),term(w,Y)).
(expression(X,Y)term(X,Y)).
(term(X,Y)factor(X,Y)).
(term(X,Y)factor(X,U),timesdiv(U,lV),term(W,Y)).
(Jactor(X,Y)ident(X,Y)).
(Jactor(X,Y)number(X,y)).
(Jactor([(IX],Y)expression(X,[)ll1))
Which after macro contraction becomes:
184
factor
factor
factor
=>
=>
=>
ident.
number.
[(], expression, [)].
The final grammar still contains some errors, which are leaft for
the reader to find.
The whole session took approximately 10 CPU minutes, and we
supplied 35 facts. To see the utility of the pruning strategy, note that
the size of the unpruned refinement graph up to depth 5 is
196,325,668. Although some of the grammar rules found in this
session are in that depth, the maximal number of clauses searched for
each goal was 68.
Appendix n. Listings
In some
PDS5.
MIS.
4.3
PDSREF.
DCGREF.
The
refinement
operator
for
definite
clause
of
inferring
the
subset
of
Pascal,
in
Appendix I.
MISRG.
The
pruning
breadth-first
search
algorithm,
4.4
PDS6.
The
interactive
debugging
system,
described
in
Section 5.3.
PDSRG.
PDSDB.
Data
base
module
for
all
systems,
and
Utility
procedures.
These
are
all
the
utility
186
PDSINI.
TYPE.
XREF.DEF
8Y8tem(_),
( stolen
from
here ) .
The files above contain all the code needed to run the systems
described in the thesis on the Prolog-IO.
top level procedure of the system also contains the list of files it
requires to run.
Some statistics on the size of the systems is provided in Figure 7.
A number that does not appear there is the total number of clause in
the systems, which is 319.
POSDC
POS5
Words
121
650
30
162
37
158
PDSREF
121
573
DCGREF
41
15 5
MIS
MISRG
45
267
MISSRC
36
173
POS6
87
401
POSRG
24
255
PDSOB
168
758
TYPE
107
438
OSUTIL
296
1041
1123
24
5031
Tota I:
187
188
stack overllow(P,S} +write/(['Error. stack overflow on ',P,'. diagnosing ... ' J) , nl,
( lind 100p(S,SI) -+ check - segment(Sl}
chec C segment(S) ).
lind loop([(P-Q)ISJ,Sloop) +looping segment((P-Q),S,SI}
lind 100p(S,Sloop).
_
-+
Sloop=[(P+-Q)IS1] ;
looping _segment((P-Q),[(Pl+-Ql)I51 ,[(Pl-Ql)ISm same _goal(P,Pl) -+ writel([P, is looping. 'J), nl, Sl=n ;
looping_ segment((P-Q),S,S/).
'
check_segment([(P-Q),(Pl-Ql}I51) +
query( legal_ call,(P,Pl),true) -+
check_segment([(Pl+-Ql)IS) ;
189
false subgoal(P,(Ql,Q2),PI,Q) i% search for a subgoal Q of P to the left of PI that returned a false
%solution.
Ql\==PI,
( query(forall,Ql,false)- Q=Q! i false _ subgoal(P,Q2,PI,Q) ).
%An interpreter that monitors errors
%see Program 12, page 78
msolve(P,X) imsolve(P,25,X), ( X\==true, ! i true ).
msolve(A,O,(overflow,[])) i- !.
msolve((A,B),D,S) i- !,
msolve(A,D,Sa),
( Sa=true - msolve(B,D,Sb), S Sb j S-Sa ).
msolve(A,D,Sa) isystem(A)- A, Sa=true i
Dl is D-l,
setojO((A,B,Sb), (c1ause(A,B), msolve(B,Dl,Sb)),R),
result(R,A,Sa).
result(R,A,(overflow,[(Ai-B)ISt])) i
member(A,B,(overflow,St)),R), !.
result(R,A,false) imember(A, , false),R),! i
member(A,B;true),R), fact(A,false) ,I,
false solution(A) j
fact(A,true), \+(member(A, _ ,true),R)), !,
missi ng _ solution(A).
result(!J,A,false) iattribute(A,total),!,
writel(!' Error trapped: no solution to ',AD, nl,
missing _ solution(A).
result{lAl,A2IR],A,false) iattribute(A,determinate), !,
write/(!' Error trapped: too many solutions to ',AD, nl,
member(A, _ , _),[Al,A2IRD, query(foral/,A,false), !,
false solution(A).
result(R,A,true)
member(A,_,true),R).
190
%%%%%PDS5.
initialized -+ true;
% these files are required to run pds.
[' zref.de!,], [pdsdc,pdsdb,pdsi nil, compile( [dsutil,type]),
assert(i nitialized).
+-
%A diagnosis system
%see Program 11, page 67
pds +nl, read(' ,p), (P exit ; solve_and _check(p), pds ).
solve and check(P) +bagojO(P ,x),solve(P.X).S), confirm _solutions(P,S).
confirm _so/utions(P,[(Pl,x)Is)) +
member((Pl,(overflow,X)),S) -+ stack - overflow(Pl,X) ;
write/(['solution: ' ,Pl, ' j ']),
( ( system(Pl) j fact(Pl,true) ) -+ n/, confirm_so/utions(P,S) j
confirm(' ok') -+ assert_fact(Pl,true), confirm_so/utions(P,S) ;
assert_fact(Pl,false), false_so/ution(Pl) ).
confirm so/utions(P,O) +write( 'no (more) solutions. '),
( system(p) -+ nl j
confirm(, ok') -+ true;
ask_for_solution(p), assert_fact(P,true), missing_so/ution(p) ).
handle error(, false clause',x) +- "
write/(['error diagnosed: ', X,' is false. ']), nl, plisting(x).
handle error( , uncovered atom'.X) +- "
write/(['error diagnosed: ',X,' is uncovered. ']), nl, plisting(X).
handle error('diverging clause',x) +- !,
Write/{!'error diagnosed: ',X,' is diverging. ']), nl, plisting(X).
%%%%%MIS.
initialized -+ true;
% These files are required to run the Model Inference System
[' xrefde!,], compile([misrg,dsutil,pdsref,type ]),
+-
191
(pdsini,pdsdc,pdsdb,missrc],
assert(initi alized) .
%The Model Inference System
%see Program 13, page gg.
mis +- nl, ask for(' Next fact',Fact),
( Fact=check - check _fact(_) ;
Fact=(P,V), W true ; V: false) assert fact(P,V), check - fact(PJ;
write( '!Illegal input'), n/ ),
I, mis.
check fact(p) +write('Checking fact(s)... '), ttyflush,
( fact(P,true), \+solve(p) nl, missing solution(p), check fact( );
/act(P./alse),8olve(p) nl, false Bolution(p), check fact( );
write('no ;-rror found. '), nl ). solve(p) +
solve(P,X),
(X (overflow,S) - nl, stack_overflow(P,S), solve(p); true ).
handle_error(' false clause' ,x) +writel([' Error diagnosed: ',X,' is false. 'n, nl,
retract(X), plisting(X).
handle error( 'uncovered atom ',x) +writel(['Error diagnosed: ',X,' is uncovered. 'n, nl,
search for cover(X,C),
assert(l5), pTisting(x).
handle error(' diverging clause' ,X) +writel(!' Error diagnosed: ',X,' is diverging. 'n, nl,
retract(X), plisting(X).
+-
assert(value(search strategy,adaptive)).
%%%%%PDSREF.
%General refinement operator for pds
+- public
192
refinement/2,
create io/2,
derefi/2.
refinement(((P-Q),(Vi,Vo ,Vf)),((P-Q) ,(Vi, IJ,[ J)))
% Close a clause
Vo\==IJ,
unisubset(Vo,Vi),
eqdifset(Vf,Vo,[]) ,
noduplicate _atom(P,Q).
193
qconc(Q,Ql,Q2).
body goal(P,Q,QVi,QVo)
-called(P, Q),
input vars( Q,QVi), output vars(Q,QVo).
-
qconc(A,true,A) - !.
qconc(A,(B,X),(B,y) -!, qconc(A,X, y)'
qconc(A,B,(B,A) ).
%unisubset(Vl,V2) - Vl is a subset of V2
unisubset(U,_) - !.
unisubsetXJVl),V2) +dmember(X,V2, V3), unisubset(Vl,V3).
% dmember(X,Ll,L2) - the dil/erence between list L1 and list L2 is X.
dmember(X,[X1L),L).
dmember(X,[11L1),[l1L2)) +amember(X,Ll,L2).
%check no goals with duplicate inputs
noduplicate atom(Pl,(P2,Q)) -!,
( same_goal(Pl,P2),!, fail; noduplicate_atom(Pl,Q) ).
noduplicate atom(Pl,P2) same goal(Pl,P2),!, fail; true..
_
194
create ioP-Q),(Xi,xo,Xm
atom vartype(P,Vi,Vo),
create iol(Vi,Xi,Vo,Xo,D,Xf,Q).
% free _ vars(vf,Vi,Vo,V/l) - remove from Vf Vi, and add Vo, getting V/l.
free _ vars(V/,Vi,Vo,Vj2) eqdifset(Vf,Vi,V/l),
append(V/l,Vo,Vj2).
%%%%% DCGREF
% Refinement operator for definite clause grammars.
% See definition of P2' Page 123:
- public
refinement/2,
create _ io/2,
ntlisting/O,
cleamt/O.
195
Vi\== II ,
nontenninal(Q),
Q= .. [F,Q',Qo],
Vi=[Qi], Vil=(Qo],
\+ P= .. [F,l'i, _I, l'i==Qi )),
qconc(Q,Ql,Q2).
qconc(A,tro e, A) - !.
qconc(A,(B,X),(B,y)) - !, qconc(A,X,y).
qconc(A,B,(B,A)).
% create the input set Xi and output set Xo and Iree set XI 01 variables
%01 a clause P-Q. does also typecheking.
create _ ioP- troe),([Xi) ,[Xi) ,[Xo))) P .. [_ ,Xi,Xoj .
ntiisting nonterminal(X), \+system(X), plisting(X), fail ; troe.
clearnt
nontenninal(X), \+system(X) , X
-+
true
106
fact solve(A,O,(overflow,nl) +- !.
fact -solve((A,B),D,S) +- !,
-fact solve(A,D,Sa),
( Sa - true- fact _ solve(B,D,Sb), S=Sb i S Sa ).
fact solve(A,D,Sa) +-system(A) - A, Sa=true ;
fact(A,true)- Sa=true;
D1 is D-1,
clause(A,B), fact solve(B,D1,Sb),
( Sb=true- Sa=true i
Sb=(overflow,S) - Sa=(overflow,((A+-B)ISJ) ).
_
107
refuted/I.
% A pruning breadth-first 8earch of the refinement graph.
% see Program 17, page I2Q.
8earch _for _ cover(P,Glau8e) n/, write/(['Searching for a cover to ,P,' ']), n/,
mgt(P,Pl), create ioPl-true),Vs),
search _for _cover((((Pl-true),Vs)lXs],xs,P,Clause,l).
...
% search for cover(Head,Tail,Goal,Glause,Length) % The IlSt between Head and Tail is the current queue of clause8.
% search in it for a true Clause that covers Goal
% Whenever you take a clause from the Head of the queue, add
% all its refinements that cover Goal to Tail, setting it to
% the new Tail of the queue. Length is the number of clauses
% searched so far.
search_for _ cover(Qhead,Qtai/,P,C,Qlength) Qhead==Qtail,
writel((,Failed to find a cover for ',P,'. queue is empty']}, nl,
!, fail.
search _for _ cover((XlQhead),Qtail,P,Glause,Qlength) X (Xclause,_), writel((,Refining: ',XclauseJ), nl,
bagojO(Y,Xt( re/inement(X,Y), covers(Y,p) ),Qnew),
length(Qnew,Qnewlength),
Qlengthl is Qlength + Qnewlength,
% writel('New refinements:'IQnew],v,n/), n/,
check refinements(Qnew,Qhead,Qtail,P,Clause,QlengthI).
check refinements(Qnew,Qhead,Qtai/,P,Clause,Qlength) member( Clause,Cv),Qnew), good clause( Clause,Cv),Qlength).
check refinements(Qnew,Qhead,Qtail,Clause,Qlength)
-;;ppend(Qnew,Qnewtail,Qtail),
search_for cover(Qhead,Qnewtail,p,Clause,Qlength).
_
good clause((X,(Xi,U,U,L)
-writel([,Checking: ',X)), n/,
( refuted(X) ,!, writel(('Refuted: ',X)), n/, fail ;
100ping(X) ,!, writel((,Looping: ',X), n/, fail ;
writel((, Found clause: ',x), n/,
write/((, after searching ',L,' clauses.'J), nl ).
looping( P-Q)) \+Iegal _ calls(P,Q).
refuted((P-Q -
198
confirm solutions(P,[(Pl,(overflow,S))!) - !,
stack over flow(Pl,S),
solve -and check(P).
confirm so/utio;-s(P,[(Pl,fa/se)J) - !,
solVe and check(P}.
confirm _solutio;-s(P,[(Pl ,X)I SJ) write/([' solution: ',Pl, ' j '!),
( ( system(Pl) j fact(Pl,true) ) -+ nl, confirm solutions(P,S) ;
confirm(' ok ') -+ assert fact(Pl,true), confirm - solutions(P,S);
assert fact(Pl,Jalse), false olution(Pl), solve and check(/') .
confirm soiUtions(P,I!) write( 'no (more) solutions.'),
( system(P) -+ nl j
confirm(' ok'} -+ t rue ;
missing solution(p), solve _ and _check(p) ).
_
199
[(false, true),
(true, retract(X)),
(r, ( ask _for(['with what'I,C),
retract(X), assert( C) ) ),
(m, (mgt(P,Pl), clause(Pl,QI,_), verify((P+-Q)=(Pl+-QI))),
%can't use Ref because of a Prolog bug.
modify((Pl+-QI),Y}, retract(X), assert(Y) ) )
I ),
plisting(P),!.
handle error('uncovered atom' ,J') +-!,
write/([' Error diagnosed: ',P,' is uncovered. 'J), nl,
ask then do(
['add (y) o-;(m)odifY a clause 'I,
[(false, true),
(true, ( ask for('which',C), assert(C) ) ),
(m, ( ask /or('which ',01),
(01 ( _ +- _),!, retract(CI), C Cl;
CI=any,!, mgt(P,Pl), O-(Pl+-true) ;
C-(Ol+-true), retract(Cl ) ),
modify(C,P,Y}, assert(Y) ) )
)
I ,
plisting(p), !.
handle _ error('diverging clause',(P+-Q)) +-!,
write/(['Error diagnosed: ',(P+-Q),' is diverging. 'J), nl,
X (P+-Q),
ask then do(
[-;;'etract(y), (m)odify, or (r)eplace it'1,
[(false, true),
(true, retract(X)),
(r, ( ask _for(['with what'I,C),
retract(X), assert(C) ) ),
(m, (mgt(P,Pl), clause(Pl,Ql, ), verify(((P+-Q)=(Pl+-Ql))),
%can't use Ref because 0/ a Prolog bug.
modify((P1+-QI),y), retract(X), assert(Y) ) )
I ),
plisting(p),!.
modify(X,Y) +reason(P,X), modify(X,P,y).
modify(X,P,y) +search _ rg(X,P,Y), confirm(ok), ! ; break(modify(X,P,Y)).
reason(P,X)
+-
200
reasonl(P,X) - true;
ask lor(['What is a reason lor ',X],P)a8sert(reasonl(X,p)}.
- assert(value(search_strategy,eager)).
%%%%%PDSRG.
%A bug-correction algorithm.
%See Algorithm 8, Page 146.
search rg(X,P,y) - % search lor Y that covers P, starting Irom x.
c-;:eate io(X,Vx},!,
search- rgl((X,Vx},P,Y).
search rgl(X,P,Y) c"Overs(X,p}, X (Xc, ), \+looping(Xc}check _ relinement-;"(IX] ,Xs,Xs,P,Y,I} ;
dereline(X,XI,P), search _ rgl(Xl,P,y)'
%dereline(X,Y) - Y is the result 01 derelining X. which means,
%in the meantime, omitting the last condition Irom x.
dereline((X,Vx),Y, _) writel(['Derelining ',x,'...')), nl, derelinel((X,Vx),Y).
derelinel(((X-Xs),Vx),Y) deconc(Xs,Ys), create io((X-Ys),Vy), new(((X-Ys),Vy),Y).
derelinel(((X-true),Vx),((Y....,:true),Vy +mgt(X,Y), \+variants(X,Y), create _io((Y-true),Vy).
_
201
202
assert(solutions(P,S).
ask for solution(p) - nl, ask for([ ' Query: . , 11 , v, (V: true;V: false)),
( V: false - fail;
ground(p) - true;
varand(P,Pvars ),
re peat ,
writel(['Which ',Pvars,'! ']), ttyflush,
reade(Answer),
(Answer=false, !, fail;
Answer=Pvars - true;
write('does not uni/y; try again'), nl ),
( attribute(P,determinate),! j true)).
_
!,
203
clear
abolish(solutions,2),
abolish(legal_ call,2).
facts +- solutions(P,S),
confirm(['Retract ',solutions(P,S)]),
retract(solutions( P,S)),
fail; true.
declare(P,A}, where
P is, for example qs( +[x],-[x]), and
A is, for example [determinate,totaij
+-
!,
!,
204
nonterminal(p), P= L,Pi,Po].
..
205
-mode(member(? ,+)).
member(X,IXJ _]).
member(X,I _IL]) - member(X,L).
append(IJ,L,L).
append([XJLII,L2,[XJL3]) - append(L I,L2,La).
reverse(X,l1 - rev(X,II,l'J.
rev([XJXs),Ys,Zs) - rev(Xs,[XJYsJ,Zs).
rev(II,Xs,Xs).
set(P,V) retracl(value(P,_)),!, set(P,V) ;
assert(value(P, V)).
addl( P,Vl) retract(value(P,V)) , integer(V), !,
VI is V+I, assert(value(P,Vl)) ;
writel(['no value for ',P,', initializing it to I')), n/,
set(P,O) , Vl=l.
ask for(Request,Answer,Test)
- repeat,
ask for(Request,Answer), Test, !.
ask_for(Request,Answer) repeat,
writel(Request), write( '7 ') , ttyflush,
reade(X),
( direclive(X) ,!,
( X,! j writer ?'), nl ),
ask for(Request,Answer) j
Answer X ),!.
onfirm(p) ask_for( P, V),
(V: t ru e,!, true j
V: false,!, fail j
confirm(p) ).
206
207
lettervars(X) varlist(X,VI) ,
% sort(VI,V2),
VI=V2,
unify vars(V2,
I'X' t ;Y' t 'Z', 'U','V','W', 'Xl' , 'Y!', 'ZI' ,'UI','VI', WI ,
'X2', '}'2',' Z2', 'U2', 'V2 ', 'W2','X3', '}'3', 'Z3 ' , 'U3' . 'l'3'. ''3',
'X4'. ' Y4' : Z4', 'U4','V4','W4']), !.
'
'
unify_vars([XlLI],IXlL2j) +- !,
unify vars(LI,L2).
unify_vars([_ILI],I_IL2j) +- !,
unify_vars(LI,L2) .
unify_vars(_,_) .
break(p) - portray(p), nl, call(break).
- mode varlist(+,-) .
% var1ist(T,L,1 J) - L is all occurances of distinct variables in term T
varlist(X,L) - varlist(X,L,IJ) , L
- mode variist(+,-,?) .
varlist(X,IXlL],L) - var(X) ,L
varlist(T,LO,L) - T . . IF1A],
=
!,
varlist1(A,LO,L) .
208
liBt to and(VB,Vsl).
liBt to andm,true) +- !.
liBt -to-and(lX],x) +- !.
liBt- to- and([X)XB],(X,YB)) +-!,
- IiBt_to_and(XB,ys).
and_ to_liBtX,Y),[XJZJ) +-!,
and_to _liBt(Y,z).
and to liBt(true,[)) +- !.
and- to -list(X,[X]) +- !.
and member(P,(P,Q)).
and = member(P,(Pl,Q))
and member(P,p}.
!, and_member(P,Q).
+-
+-
X, foralll(S).
portray(X) +
lettervarB(X),
portrayl(X,6),
fail.
portray(X).
portrayl(X,N) +
Nl is N-I,
( var(X),!, write(X) ;
atomic(X), !, write(X) ;
N O,!, write('#) ;
X I_LI, I, writer!'), porlray_liBt(X,NI,5), write('I') ;
X ( _,_ ) , I, wrlte(T), portray_and(X,Nl), writen') i
X .. [FlA), I, portray_term(F,A,NI) ;
break(portrayl(X,N)) ).
portray_ args(X,N) +
X U, I, true i
X In I, portrayl(Y,N) ;
X IYJYBI, I, portrayl(Y,N), writer, '),1, portray_args(Ys,N).
209
portray Iist(X,N,D) +
vX), !, portrayl(Y,N) j
X O,!, true j
D=O,!, write('. . #') j
X IYlIJ, ==O,!, portrayl(Yl,N) ;
X IYlIl, var(),!, portrayl(Yl,N), write('1 '),!, portrayl(,N)
X IYI,IYsl,!,
portrayl(YI,N), write(', '), DI is D-I,!,
portray _ list(llYsl,N,DI ) j
X (YlIl,!, portrayl(Yl ,N), write( ' I ' ) ,!, portrayl(,N).
portray and(X, N) +vX),!, portrayl(X,N)j
X (Y,Ys),!, portrayl(Y,N), write(' : ), !, portray - and(Ys,N)
portrayl(X,N).
portray term(F,IAJ,N) +- ctl rrent op(P,T,F),!,
write(F), write(' '), portrayl(A,N) .
portray _ term(F,IA,B),N) +Ctl rrent op(P, T,F), !,
portray ifA,N), write(F), portrayl(B,N).
portray term(F,A,N) +write(F), write('('), portray args(A,N), write(') ') .
_
210
ll.12 Initialization
%%%%% PDSINI.
% initialization stuff.
declare(qsort(+[x],-[x]),[determinate,totaij).
declare called(qsort(X,Y),
[qsori(Z,U),partition(V,W,Xl,Yl ),append(Zl,U l,Vl ),c(Wl,X2,1'2)]).
declare(parti lion(+[x],+x,-[x],-[x]),[determi nate,total]).
declare called(parlition(X,Y,Z,U),
[pariition(V,W,Xl,Yl),Zl<Ul,Vl=<Wl)).
declare(append( +[x],+[x],-[x]), [determinate, total]).
declare
called(append(X,Y,z),[append(U,v,W)]).
declare(/e(+0,+0),[determinate]).
declare called(le( , ),[/e(Z,U)]).
declare{insert(+x,+[xl-[x]),[determinate,tota/]).
declare called(insert(X,Y,Z),[insert(U,V,W),X2<Y2,Xl=<Yl]).
declare(isort(+[x],-[x]),[determinate,totaij).
declare called(isort(X,Y),[isort(Z,U),insert(V,W,Xl)]).
- declare(+x'=< '+x,[determinate]).
- declare( +x'< '+x,[determinate]).
_
211
%%%%%7YPE
%%%%Typing utilities for pds
+-
public
term to vars/2,
typed-=-te-;;"/2,
atom_vartype/3,
vartype/4,
type _ check/I.
+-mode type(?,?,-,-).
% type(Type ,Name,Terms,TermsType).
type(x,object,[J,[J).
type(0, integer ,[O ,s( _ ),[s (O )) ).
type(l,integer,[O),[)).
type(lO,boo lean,
[O,l,not( ),and( , ),or( , ),
[not(OI),and(Ol,Ol),lW{Ol,Ol)]f"
type( io,binary,[nil,o(_ ) ,i( _ ),[o(io),i(
. io)]).
type([J,list,[[],[ I Il,[[allll))
type((x1,' lis t O/'JII,[ I II, [[XI [XI]])
type(bt(L ), 'binary tree[leaj{_ ),t( _, _ ),[leaj{L),t(bt(L), bt(L) )).
type(lbt(X), 'la beled binary tree',
[ nil,t( _ , _ , _ ),[t(lbt(X),x,lbt(X)))).
type(tu( L),' two-three tree',
[leaj{_ ),t(_, _, _ ),[leaj{L),t(L,L,[ ttt(L)) )).
type( terminal,terminal,[X],[]) +terminal(X).
+-
212
type(Type,_, _ ,1YPedTerms),
member(Term,TypedTerms).
setol_vartype((Term,TermType),Vars) setoJ((Var,7).tpe),vartype(Term,Term7).tpe,Var,Type),Vars), !.
setol_vartype((Term,Term7).tpe),D).
213
type check((P,Q)) - !,
-type _ check(PJ, type check(Q).
type check(Atom)
-type(Atom,_,_,IAtomTypel),
type check(Atom,AtomType).
_
..
(which
I have
I am referring
-+
Q j R.
Y to select the
214
cut,
negation-as-failure.
Conventional high-level languages, such as Pascal and modern
Lisp enjoy an established and mature users community, who has
developed over the years a deep understanding of the formalism used,
a rich set or programming idioms, an d a refined programming style.
In
contrast,
computing ,
in
Prolog
represents
rather
new
approach
to
at
expanding
the
arsenal
of
programming
Unsuccessful
styles
and
References
[1]
A.
H.
Abo and
J. D.
Ullman.
Prentice-Hall, 1972.
[2]
Dana Angluin.
Finding patterns common to a set of strings.
Journal of Computer and SY8tem Science8 21:46-62, 1980.
[3]
Dana Angluin.
Inference of reversible languages.
Journal of the ACM29:741-765, 1982.
[4J
Dana Angluin.
A note on the number of queries needed to identify regular
languages.
Information and Control, to appear.
[5]
Dana Angluin.
Term sequence inference.
1982, in preparation.
[6]
[7]
[8]
Robert Balzer.
Automatic Programming.
216
[9]
A. W. Biermann.
The inference of regular Lisp programs from examples.
IEEE Tran8action8 on SY8tem8, Man, and CybernetiCB
A. W. Biermann.
On the inference of Turing machines from sample
computations.
Artificial Inelligence. 3:181-198, 1972.
[11]
[12]
[131
[141
P. Brazdil.
A Model of Error Detection and Correction.
Martin Brooks.
Determining Correctne88 by Te8ting.
217
[17]
[IS]
Timothy A. Budd.
Mutation AnalY8.i8 of Program Te8t Data.
[20]
Lawrence Byrd.
Prolog debugging facilities.
19S0.
Technical note, Department of Artificial Intelligence,
Edinburgh University.
[22]
J.
A. K. Chandra, D.
Alternation.
C.
[24]
C. L.
Chang and R.
Kozen, L.
J.
Stockmeyer.
C. T.
Lee.
218
[25]
Keith L. Clark.
Ne gation as failure.
In
[26]
K. L. Clark and
S.-A. Tarnlund.
Logic Programming.
W.
Programming in Prolog
Spr inger
[28]
Verlag,
1982.
Colmerauer.
Metamorphosis grammars.
In L. Bole (ed itor ), Natural language communication
computers,. Spr in ger-Verla g, 1978.
Alan
with
[29]
Alan Colmerauer.
Infinite trees and ine qua litie s in Prolog.
In Proceedings of the Prolog Programming Environments
Workshop. Datalo gi, Linkoping, Sweden, March, 1982.
To appear.
[30]
S. Crespi-Reghizzi.
An effective model for grammar inference.
In Information Processing 71, pages 524-529. North-Holland,
Amst erd am, 1972.
[3 1]
[32]
219
[33J
[34J
[35J
[36J
R. W. Floyd.
Assigning meanings to programs.
In J. T. Schwartz (editor ), Proceedings of Symposium
Applied Mathematics, pages 19-32. American
Mathematical Society, 1967.
in
[37]
[38]
E. Mark Gold.
Limiting recursion.
Journal of Symbolic Logic
30, 1965.
[39]
E. Mark Gold.
Language identification in the limit.
Information and Control 10:447-474, 1967.
[40]
E. Mark Gold.
Complexity of automaton identification from given data.
Information and Control 37:302-320, 1978.
on
220
[41]
SE-l:156-173,
June, 1975.
[42]
C. Cordell Green.
Theorem proving by resolution as a basis for question
answering.
In B. Meltzer and D. Michie (editors), Machine Intelligence 4,
pages 183-205. Edinburgh University Press, Edinburgh,
1969.
[43]
S. Hardy.
Synthesis of LISP programs from examples.
In Proceedings of the Fourth International Joint Conference
on Artificial Intelligence, pages 268-273. IJCAI, 1975.
[44]
Carl Hewitt.
Description and Theoretical Analysis (Using Schemata) of
Planner: a Language for Proving Theorems and
Manipulating Models in a Robot.
C. J. Hogger.
Derivation of logic programs.
Journal of the ACM 27:372-392, April, 1981.
[47]
William E. Howden.
Algebraic program testing.
Acta Informatica 10(1):53-66, 1978.
221
[48]
J. D. Ichbiah et al.
Preliminary Ada reference manual.
ACM SIGPLAN Notices 14(6), June, 1979.
Part A.
[49]
Ingalls, Daniel H.
The smalltalk-76 programming system: design and
implementation.
In Conference Record of the Fifth Annual ACM Symposium
on Principles of Programming Languages, pages 9-16.
Association for Computing Machinery, January, 1978.
[50]
Kenneth E. Iverson.
A Programming Language.
[53]
[54]
4:331-358, 1980.
222
[55]
[56]
[57]
Robert A. Kowalski.
Predicate logic as a programming language.
In Information Processing 74, pages 569-574. North-Holland,
Amsterdam, 1974.
[58]
Robert A. Kowalski.
Algorithm
Logic + Control.
=
[59]
July, 1979.
Robert A. Kowalski.
Logic for Problem Solving.
P. Langley.
Language Acquistion Through Error Recovery.
SE-4:199-229,
May, 1978.
[62]
Frank
G.
McCabe.
223
[63 ]
[64]
Drew V. McDermott.
The Prolog phenomenon.
SIGAKT Newsletter 72, July, 1980.
[65 ]
R. S. Michalski.
Pattern recognition
as
[66]
PAMI-2:349-361, 1980.
[67 ]
[68 ]
T. Mota-oka et al.
Challenge for knowledge information processing systems
{preliminary report on fifth generation computer systems}.
In Proceedings of Internation Conference on Fifth Generation
Computer Systems, pages 1-85. JIPDEC, 1981.
[69]
P. Naur.
Programming by action clusters.
BIT 9:250-258, 1969.
[7 0]
P. Naur
&
B. Randel, Eds.,
Software Engineering.
224
[71]
[72]
Alan J. Perlis.
Controlling software development through the life cycle model.
In A. J. Perlis, F. G. Sayward, and M. Shaw (editors), Software
Metrics, pages 95-110. The MIT Press, 1981.
[73}
Gordon D. Plotkin.
A note on inductive generalization.
In B. Meltzer and D. Michie (editors), Machine Intelligence 5,
pages 153-165. Edinburgh University Press, Edinburgh,
1970.
[74]
Gordon D. Plotkin.
Automatic Methods of Inductive Inference.
[76}
Gordon D. Plotkin.
A further note on inductive generalization.
In B. Meltzer and D. Michie (editors), Machine Intelligence 6,
pages 101-124. Edinburgh University Press, Edinburgh,
1971.
Wolfgang H. Polak.
Theory of Compiler Specification and Verification.
Karl R. Popper.
The Logic of Scientific Discovery.
Karl R. Popper.
Coniectures and Refutations: The Growth of Scientific
Knowledge.
225
[79]
Scott Renner.
A Comparison of PROLOG systems available at the University
of Illinois.
April, 1982.
Internal report UIUCDCS-F-82-897, Knowledge Based
Programmer's Assistant Project, University of Illinois.
[80]
Scott Renner.
Location of Logical Errors in Pascal Programs with an
Appendix on Implementation Problems in Waterloo
Prolog/C.
April, 1982.
Internal report UIUCDCS-F-82-896, Knowledge Based
Programmer's Assistant Project, University of Illinois.
[81]
C. Rich.
Initial report on the Lisp programmer's apprentice.
"IEEE Transactions on Software Engineering SE-4(6):342-376,
1979.
[82]
C. Rich.
Formal representation of plans in the Programmer's
Apprentice.
In Proceedings of the Seventh International Joint Conference
on Artificial Intelligence, pages 1044-1052". IJCAI, 1981.
[83]
J.
A. Robinson.
226
[86]
P. Roussel.
Prolog: Manuel Reference et d' Utilisation.
[88]
Erik Sandewall.
Programming in an interactive environment: the LISP
experience.
Computing Surveys , March, 1978.
Ehud Y. Shapiro.
Inductive Inference of Theories from Facts.
Ehud Y. Shapiro.
An algorithm that infers theories from facts.
In Proceedings of the Seventh International Joint Conference
on Artificial Intelligence. IJCAI, August, 1981.
[90]
Ehud Y. Shapiro.
The model inference system.
In Proceedings of the Seventh
on Artificial Intelligence.
Program demonstration.
[9 1]
Ehud Y. Shapiro.
Alternation and the computational complexity of logic
programs.
In Proceedings of the First International Logic Programming
Conference. ADDP, September, 1982.
[92]
Daniel G. Shapiro.
Sniffer: a System that Understands Bugs.
227
[9 3}
[94]
[95]
Douglas R. Smith.
A survey of synthesis of LISP programs from examples.
In International Workshop on Program Contruction, Chateo
de Bonas. INRIA, 1980.
[96]
[97}
Philip D. Summers.
Program Construction from Examples.
[99 ]
Phillip D. Summers.
A methodology for LISP program construction from examples.
Journal of the ACM 24:16 1- 175, January, 1977.
North-Holland, 1975.
Number 1:
A Computer Model
228
(2):11, 1981.
[ 105J R. M. Wharton.
Grammar enumeration and inference.
Information and Control 33:253-272, 1977.
[106J L. White and E. Cohen.
A domain strategy for computer program testing.
IEEE Transactions on Software Engineering SE-6, May, 1980.
[107J P. H. Winston.
Learning structural descriptions from examples.
In P. H. Winston (editor), The Psychology of Computer Vision,
McGraw-Hill, New York, 1975.
[108] Niklaus Wirth.
Program development by stepwise refinement.
Communications of the ACM 14:221-227, April, 1971.
229
Program8.
231
Index
86
Knobe, K.
85 , 88, 89
Angluin, D.
Apt, K. R.
Balzer, R.
89
Kowalski, R. A.
15, 16, 21
88
88
Lipton, R. J. 8
Langley, P.
Biermann, A. W.
Blum, L.
Kodratoff, Y.
Lintz, R. F.
McCabe, F. G.
Budd, T. A.
McDermott, D. V.
Blum, M.
11
88
Bundy, A.
Manna, Z.
74
Mitchell, T. M.
Case, J.
85
Mostow, D. J.
Chandra, A. K.
Clark, K. L.
16, 54
Naur, P.
121
88
Crespi-Reghizzi, S.
12
Demilio, R. A.
12
23
Colmerauer, A.
Davis, R.
Pereira, F. C. N.
8, 9
Plaisted, D.
44
87, 88
Plotkin, G. D.
6, 10
Popper, K. R.
15 9
Gold, E. M.
Goodenough,J. B.
Green, C. C.
Guiho, G.
10
Randell, B.
Robinson, J. A.
89
33
Hayes-Roth, F.
Hewitt, C.
15
89
Sandewall, E.
Harel, D.
121
Perlis, A. J.
Polak, W. H.
Gerhart, S. L.
160
88
87
Michalski, R. S.
12
Shaw, D.
89
Siklossy, L.
89
88
Silver, B.
79
Smith, D. R.
Jouannaud, J. P.
89
10, 164
Smith, C. H.
Soloway, E.
89
85
13
Klahr, P.
12
Summers, F. D.
Knobe, B.
86
Sussman, G. J.
12
232
Swartout, W.
Sykes, D.
89
89
Van Emden, M. H.
76
Waldinger, R.
Warren, D. H. D.
Wharton, R. M.
Winston, P. H.
Wirth, N.
88
8, 124
Yelowitz, L.
Young, R. M.
6
88