Beruflich Dokumente
Kultur Dokumente
00
Printed in Great Britain. All rights reserved Copyright © 1992 Pergamon Press Ltd
A L T E R I N G A N D APPLYING PREDICATES
H. JUSTIN COVEN~"
Computer Science Department, Arizona State University, Tempe, AZ 85287-5406, U.S.A.
Abstract--A set of tools in Prolog for manipulating predicates as first-class objects is described. These
tools are higher-level tools than assert, retract and querying. The first group of these tools are analogs
to the Lisp tools apply, function, lambda, and programming cliches such as mapcar. The second group
of tools is for editing and manipulating predicates. Prolog provides a simpler structure for predicates than
Lisp has for functions and thus a small set of tools for adding to, retrieving from, removingfrom, replacing
to, and exchanging within predicates can be provided for Prolog predicates but not for Lisp functions.
1. I N T R O D U C T I O N
In this article we will develop a set of tools in Prolog for altering and applying Prolog predicates.
The uses of these tools will be at least 3-fold: (1) they will be used as a programming cliche [1]
that can apply a function to an entire list, one element at a time; (2) they will be used to construct
unnamed predicates as the program is running and then call or apply those predicates; and (3) they
will be used as a set of editing tools that can manipulate predicates in the database without loading
or unloading a file into the database. (1) and (2) Give Prolog m a n y of the powerful program
manipulating language features that languages like Lisp have; (3) goes beyond what Lisp has by
providing a set of tools for manipulating predicates (Lisp's parallel is functions) without having
to deal with the details of clause manipulation. Prolog provides a simpler structure of predicates
than Lisp has of functions and thus a relatively small set of tools can be created for the abstract
manipulation of predicate structure while it is difficult to do the same for Lisp.
For any language to mature it needs to develop a strong set of environmental tools. For most
languages these tools are usually pragmatic and operational in nature. Because Prolog has a close
relationship to logic many language developers have tried to remain as close to a logical foundation
as possible. Due to this, tools unrelated to logic have been shied away from and only been included
when absolutely necessary.
One of our fundamental philosophical beliefs in the development of language tools is that
any mathematical system such as logic or functions is an abstraction for doing computation.
These abstractions have some properties that make the computation more tractable for the human
mind.
Our goal in developing language tools is in contrast to Ref. [2] where the goal was to determine
if the addition of higher-order tools would give Prolog more computational power than it already
had without those tools. In Ref. [2] Warren was concerned with whether ordinary Prolog could
be used to represent the same computational problem that higher-order tools were used to represent.
This is not our concern; we are concerned with creating programming language tools that make
programming problems more tractable for the h u m a n mind. Analogously we are not concerned
with whether we can do the same problem using assembly language or machine language or a higher
level language, but rather with whether a p r o g r a m m e r can program with the different programming
language tools more easily.
It is c o m m o n knowledge that programmers on average program the same number of lines of
code during any period of time no matter what language they use. Thus it is wise to create language
abstractions that each execute a number of lines of a lower level language. The trick is to create
instructions that execute c o m m o n sets of lines of code. If there are few c o m m o n sets of lines of
fPresent address: Computer Science Department, Bellarmine College, Louisville, KY 40205-0671, U.S.A.
57
58 H. JUSTINCOVES
code, then a few new language tools can be created. We describe such a set of tools for manipulating
a Prolog database.
In Section 2 we develop a Prolog analog to Lisp's "lambda", "apply", "mapcar" and other
programming cliches. In Section 3 we describe how to use these tools to manipulate a program's
self-representation. The set of tools described in Section 4 is a set of environment tools for editing
a Prolog database.
2. APPLY AND P R O G R A M M I N G C L I C H E
In this section we develop a set of programming cliches analogous to those that exist in Common
Lisp [1]. The cliches we will be building up to are the mapcar and associated functions that apply
a given function to an entire list of arguments one list element at a time. In Prolog there is a clear
concept of what a list is, but not well defined concepts of what a function is or how to apply it.
Trying to query a Prolog database is analogous to making a function call, when a query like "?-
likes(john, sally)" is made it is as if the function "likes" is called with the arguments "john" and
"sally". These arguments are paired with the formal parameters " X " and " Y " of a clause in the
database (the called function) such as: "likes (X, Y):- boy(X), girl(Y)". The body of the clause
"boy(X), girl(Y)" can be considered the body of the function. Thus we consider a query to be a
function call and a clause in the database to be the function called.
2.1. Apply
In Lisp when a function is applied there are two arguments: a function defined in some way and
a set of arguments the function is applied to.
If we want to apply a predicate that exists in the database to some given arguments, then we
could query for that predicate with the given arguments. This will unify the arguments with the
formal parameters of the called predicate in the database and then query (execute) the body of the
predicate in the database. Thus we need to make a tool that will make a query of the predicate
attached to the given arguments. We create the predicate "apply" that takes two arguments--the
first argument is a predicate to be applied, the second argument is the list of given arguments the
predicate is to be applied to. If the predicate is a user defined predicate on a system built-in predicate
then the predicate needs to be defined by name only and the definition of apply is as follows:
apply clause 1
apply(Name, Arguments):- Query = . . [Name [Arguments], Query.
The "univ" operator " = . . " is used to create a functor with the name being the first argument
of apply " N a m e " and the arguments being the second argument of apply "Arguments". The
created functor "Query" is then queried (the above code is possible because predicate variables like
"Query" exist in many current Prolog systems such as Cprolog or Quintus Prolog).
With the above "likes" clause in the database along with the clauses: "boy(tom)" and
"girl(sally)", we could make the following query:
?- apply(likes, [tom, sally]).
yes
This example is given to demonstrate the use of "apply". Certainly we could make the equivalent
query "?-likes(tom, sally)". However with the "apply" predicate the predicate being applied (the
first argument of "apply") could be a variable and there could be a whole stream of reasoning
leading up to the apply (the apply could be embedded deep into the body of a program). In the
next subsection we will develop and "apply" mechanism that will go further than just allowing a
variable predicate, it will allow the predicate to be constructed in a program (as will be seen in
Section 3).
and the body of the function to be applied. We will use the symbol "lambda" to identify an
unnamed predicate. "lambda" Will be the name of a functor that has two arguments, the first being
the formal parameters of an unnamed predicate and the second being the body of an unnamed
predicate. A possible "lambda" functor representation of an unnamed predicate is as follows:
lambda([A,B,C], (C is A + B))
Here it is as if we have an unnamed predicate with three arguments and a body composed of
"C is A + B " . If this were named and sitting in the database it may appear as "un-
named(A, B, C) : - C is A + B". In order for our apply predicate to handle this case we add the
following clause:
apply clause 2
apply(lambda(Arguments, Body), Arguments) : - Body.
Here the formal parameters in the lambda (the first appearance o f " A r g u m e n t s " ) are unified with
the arguments the lambda is being applied to (the second occurrence of "Arguments"). Finally the
body of the lambda is executed (queried).
With only the previously defined "apply" clauses in the database we could use the following
query:
?-- apply(lambda([A,B,C,], (C is A + B)), [1,2,Return]).
A=I,
B=2,
C=3,
Return = 3
yes
We can query the mapcar predicate with two different sets of arguments in order to translate
from English to German and then English to Chinese.
? - mapcar([i, like, you], eng_german_dict, Return).
Return = [ich, gefalle, du]
yes
? - mapcar([i, like, you], eng_chinese_dict, Return).
Return = [wo, xi huan, nil]
yes
In Lisp it is possible that the function that is being passed into "mapcar" may take
more than one argument. To handle this Lisp's "mapcar" allows itself to be called with a
variable number of arguments with all additional arguments being lists. Mapcar will
recurse through each list at the same time, taking the first value of each list and applying the
function to the set of first elements from each list. This is possible because within Common
Lisp functions can take a variable number of arguments. In Prolog any given predicate has a
fixed number of arguments. Thus we force "mapcar" to take one argument list and a return
list. This forces every function being passed into "mapcar" to take exactly two arguments:
one passed in argument; and a return value. The only ways around this restriction would be
to either create a definition of mapcar with clauses for every possible number of arguments, or
to add the capability of variable argument predicates to Prolog. The former choice is ungainly
but straightforward, the latter choice being nontrivial and counter to the standard definition of
Prolog.
We can go on to define several other common programming cliches that exist in Lisp.
"remove-if-not" goes through a list applying a function to each element, if the function returns
"nil" ("no" in Prolog) then the element is removed from the list.
remove-if-not([FirstlRest], Function, [Firstl RestReturn]) : -
apply(Function, First), !,
remove-if-not(Rest, Function, RestReturn).
remove-if-not([_lRest], Function, RestReturn) : -
remove-if-not(Rest, Function, RestReturn).
remove-if-not([], _, []).
In Lisp "count-if" takes two arguments a list and a function. It counts the number of elements
in a list that satisfy the function. Here satisfy means that the function is applied to an element in
the list and returns a non-nil value (in Prolog it would be satisfied).
"find-if" Also takes a list and a function as arguments. The first element of the list that
the function satisfies is the returned value. The third arguments of "remove-if-not", "count-if"
and "find-if" are the returned values. The predicates "find-if" and "count-if" appear in the
Appendix.
The choice of returning an empty list [] as the return value when no element of the list satisfies
the function is an arbitrary choice (this is done by making the third argument of the first clause
the empty list []). It would also be appropriate for the predicate to fail in this case (the first clause
could be removed).
Numerous other similar programming cliches can be created depending upon the desires
of the programmer. Common Lisp [3] describes many additional programming cliches to choose
from.
apply clause 4
apply(lambda([_[Rest]), Args) : -
apply(lambda(Rest), Args).
We simply apply different clause one after another recursively until one succeeds. If the program
backtracks, "apply" will appropriately backtrack and retry the rest of the clauses of the "lambda".
As an example we can backtrack on the following apply:
?-- apply(lambda([[[one], true],[[two], true]]), [X]).
X = one;
X = two;
no
Here we have backtracked twice on two retries the first retry succeeding and setting " X " to "two".
With the new tools "lambda", and "apply", our programs now have the power to create and
modify their own code, because they can create predicates and then run them. Without these tools,
in order to do the same things the programmer would be forced to assert and then call predicates.
Programmers can now avoid the extra conceptual task of writing codes for asserting, determining
names, and managing the database. Additionally the programmer can work with entire predicates
and does not have to deal with asserting and retracting single clauses at a time. This saves the
programmer from conceptualizing about extra programming steps. Programming cliches, by
reducing the conceptual involvement, simplify the task of the programmer.
The ability to write computer programs that manipulate themselves is a powerful tool. There
are many intriguing issues involved with the ability of programs to manipulate themselves. The
tools presented in the previous and next sectiofis are intended as a powerful set of instructions that
will make this task (writing programs that manipulate themselves) simpler. In this section we will
describe a trivial example of a program that manipulates itself and then applies part of itself. ]'his
example is intended to give the flavor of how this task can be done using our tools. We then go
on to discuss, in this section, places where this ability can be useful.
3.1. An example
A program could create a lambda structure from arguments passed in as in "build-lambda"
shown below:
build-lambda(Conj 1, Conj2, Argl, Arg2,
lambda([Argl, Arg2], (Conj 1, Conj2))).
62 H. JUSTINCOVEN
Code could be added to perform tests to determine the proper construction of lambda. Different
conjuncts (here we define "conjuncts" to be the different functors that are conjoined together in
the body of a clause) and arguments could be tested and/or chosen from to create a lambda. All
the tools in Prolog that allow the creation of a functor can be used to create a lambda. The created
lambda could then be applied:
build-apply(Conj 1, Conj2, Argl, Arg2) : -
build-lambda(Conj 1, Conj2, Argl, Arg2, Lambda),
apply(Lambda, [tom, sally]).
We can call this program to construct an unnamed predicate and then apply that unnamed
predicate:
? - build-apply(likes(X, Y), boy(X), X, Y).
Which create the lambda structure:
lambda([X,Y], (likes(X,Y), boy(X))).
And would match the second clause of apply and call:
likes(tom, sally), boy(tom).
Which in the database we have built up would succeed and return:
X = tom,
Y = sally
yes
4. M O D I F Y I N G P R E D I C A T E S AND E D I T I N G TOOLS
In this section we develop a set of tools that modify predicates in ways that humans think of
modifying predicates. Predicates are treated as sets of clauses, the same way they are treated in
the above described apply predicate. These tools can be viewed as a set of tools for user editing
of the database, as a set of tools for a program to manipulate itself, or as a set of tools for a program
to manipulate unnamed predicates.
Some of the more common ways humans modify things are by adding to them, viewing parts
of them, removing parts, replacing parts, and exchanging parts. We will be creating a set of tools
that do these things to entire predicates, clauses, and conjuncts. The first tool (predicate) that we
describe is "addclause" which as its name implies adds a clause to a specified predicate.
Altering and applying predicates 63
All of the following tools that we propose are only able to work upon dynamic predicates they
cannot work upon static predicates. Consulting and reconsulting files create static predicates which
our tools can not operate upon. However this problem can be solved by using the reconsult and
consult defined in Section 7.13 of the standard Prolog reference text [5]. Additionally there are tools
such as the "save" of Quintus Prolog that allow the p r o g r a m m e r to store the curent database into
a file. Thus the tools defined below can be used to manipulate a storable database.
We will first define all of our tools in relation to named predicates and after we have developed
all of our tools this way we will show how it is simple to extend these to unnamed predicates. The
implementations for unnamed predicates is significantly simpler than for the named predicates.
addclause(_, _, _ ) : -
printstring("Warning clause number out of bounds").
constructargs([ ], []).
constructargs([_lRest], [XlReturnRest]) : -
constructargs(Rest, ReturnRest).
Although the lambda structure indicates the number of arguments of the specified predicate,
care must be taken so that the arguments of each clause are not matched with each other. This
is the job of "constructargs". As each clause is retracted it must be saved in variables
(ConstructedArgs and FoundBody), "ConstructedArgs" can not be the same as the arguments of
the new clause being added nor can those arguments be the same for each retracted clause.
"constructargs" creates a list of uninstantiated arguments that is the same size of the clause to be
added. Thus when a clause is retracted its arguments can be saved in that list of uninstantiated
arguments.
The third clause of "addclause" prevents the predicate from failing. If the indicated position is
out of bounds a warning should be reported. This also allows the retracted clauses to be reasserted.
Since an improperly written clause would cause a Prolog predicate to unexpectedly fail we feel that
indication of proper position of clauses should also be strict. We don't just allow the clause to be
added last if the index is out of bounds.
addconjofclause(_, _, _, _) : -
printstring("Warning clause index out of bounds").
createbody(OldConjunct, _, _, OldConjunct) : -
printstring("Warning conjunct index out of bounds").
"getconjofclause" Retrieves a specified conjunct of a specified clause. This predicate has the same
arguments as "addconjofclause" except that the fourth argument will return a conjunct instead of
providing a conjunct to be placed. The implementation technique is identical to that for
"addconjofclause". If you have predl : - a,b,c,d,e, in the database then the following query would
behave as indicated:
? - getconjofclause(predl, 1, 4, X).
X=d
yes
Using "addconjofclause" it is possible to add a set of conjuncts into a clause instead of being
limited to adding only one conjunct at a time. This can be done by simply providing a conjunction
of conjuncts as the fourth argument instead of just one conjunct. However using the syntax and
implementation we have given we can not get a set of conjuncts. It should be possible to add the
feature of dealing with sets of conjuncts to a later version of this set of tools just as it should be
possible to deal with sets of clauses in later versions.
When we place a new conjunct into the middle of an old clause we may want the arguments
in the conjunct to match up with arguments in either the head or other conjuncts of the given clause.
If we are trying to match the head this can be done using the first argument of "addconjofclause".
To match arguments of other conjuncts, those conjuncts must be replaced at the same time. We
provide "replaceclause" and "replaceconjofclause" to do tasks like this. Because our tools do not
work with sets of clauses we would have to use "replaceclause" to do this task.
Besides adding, getting, removing and replacing predicates, clauses and conjunctions, one may
want to exchange clauses or conjuncts within a predicate. We might want to move a clause or
conjunct from before another clause or conjunct to after it. We provide the predicates "exchange-
clause(PredHead, FromClause, ToClause)" and "exconjofclause(PredHead, FromClause, From-
Conj, ToClause, ToConj)" to handle these tasks. The implementations of these are similar but
slightly more involved than the implementations we have already given for "addclause" and the
other predicates. They too appear in the Appendix.
As an example use, if we have "predl : - w,x,y,z" and "predl : - a,b,c,d" in the database, then
the following would occur:
9_ exchangeconjofclause(predl, 1, 3, 2, 1).
yes
? - listing(pred 1).
predl : - w,x,a,z.
predl : - y,b,c,d.
yes
4. 7. Pattern matching
Besides adding tools for working with sets of conjuncts and clauses you could also add some
pattern matching, instead of giving numbers for the position of the conjuncts or the clauses you
could give patterns to match. A program that was self-modifying predicates would likely know
parts of predicates by composition structure not by position numbers. Thus it is useful to have a
set of tools similar to what we have already developed that operate by matching clauses and
conjunctions instead of just having tools that work with indices. This is analogous to Icon [6] which
has tools to match parts of strings along with having tools that work with indices of strings. Icon
works with strings, the tools we give here work with predicates. As an examples we have
"addclausebefore(PredName, LambdaToPlace, LambdaToMatch)". The first argument is a predi-
cate name, the second is the lambda structure of the clause that is to be added, and the third
argument is a lambda structure that is to be matched. The new clause is to be placed before the
clause that is matched.
68 H. JUSTINCOVEN
We have chosen to create a predicate that places the new clause before instead of after, so that we
can place clauses at both the very beginning and very end of the predicate. To place at the beginning
we can provide a match argument which is the anonymous variable which will match anything--
specifically the first clause of the predicate--and thus the new clause will be placed before the first
clause. If the matching clause does not match anything then the new clause will be placed after all of the
existing clauses. Using the above database created for "predl2". We could execute the following query:
The implementation of "addclausebefore" differs a little from "addclause" and appears in the
Appendix.
4.9. An editor
The tools we have provided in this section can be used as an effective set of editing tools for
manipulating the database as a programmer is writing code into the database and experimenting
in developing Prolog code. This type of environment differs from that of using an editor such as
"emacs" because files do not need to be loaded continually. Instead of editing a file we are editing
the database. It is possible that a full database screen editor could be created even with syntax
checking built into the editor. We could extend the current tools to a screen editor, but it would
be more appropriate to create this type of tool internal to a Prolog implementation. However the
editing advantages of these tools are only a nice side effect in the development of tools for a program
to manipulate itself.
5. S U M M A R Y
In this paper we have developed a set of tools for manipulating and using Prolog predicates.
Language tools are built to do common tasks that are usually done by many instructions. With
Altering and applying predicates 69
the tools the same tasks can be d o n e with one instruction instead o f many. The p r o g r a m m e r can
think abstractly a b o u t the task with a single instruction instead o f having to w o r r y a b o u t n u m e r o u s
details o f the task. In Section 2 we developed a set o f tools similar to those o f Lisp for the applying
o f predicates (functions). In Section 3 we discussed h o w a p r o g r a m ' s self-manipulation o f code can
be a very powerful tool. In Section 4 we developed a set o f tools for manipulating Prolog predicates.
This set o f tools could be used as a database editing package or as the foundation o f a set o f tools
for a p r o g r a m ' s self-manipulation o f its own predicates.
The advantage o f having such tools is that instead o f writing codes for each o f the steps o f
asserting; retracting; altering; querying; naming; m a n a g i n g the database; and dealing with
n u m e r o u s clauses o f predicates, they are n o w put into single instructions that do all o f these tasks
at once. The tools are meaningful in that they are tasks that p r o g r a m m e r s typically want to do.
There is also a small set o f these tools. In Lisp it is not as easy to create such a small set o f tools
because Lisp functions can be lists embedded within other lists to an unlimited depth.
As indicated in Section 4 further w o r k would include the extension o f the given tools to fully
handle pattern matching, working with sets o f conjuncts and clauses, working with lambdas, and
simplifying the syntax. We would also wish to experiment with these tools in the development o f
learning programs, i.e. p r o g r a m s that themselves experiment with the creation o f different
predicates for the solving o f specific problems.
Acknowledgements--I would like to thank Ed Ashcroft for his discussions on this topic. I would also like to thank the
students of a "CSC202 Functional Programming Languages Laboratory: Prolog" course I taught at Arizona State
University in the spring of 1990 for their experimentation in and comments on the implementation of some of these ~ools.
REFERENCES
APPENDIX
/* programming cliche */
/* getclause */
getclause(. . . . true) :-
printstring(
"Warning clause number out of bounds").
copypred(PredHead, CopyPredHead) :-
PredHead =.. [PredNamelArgs],
constructargs(Args, ConstructedArgs),
/* Function */
function(PredHead, lambda(LambdaList)) :-
function-aux(PredHead, LambdaList).
function-aux(_, []).
/* Add Function */
addfunction(PredName, lambda(LambdaList)):-
addfunction-aux(PredName, LambdaList).
addfunction-aux(PredName, [[Args,Body]lRest]):-
PredHead =.. [PredNamelArgs],
addfunction-aux(PredName, Rest),
asserta((PredHead :- Body)), !.
addfunction-aux(_, []).
getconjofclause(PredHead, Count,
ConjunctNum, Conjunct) :-
NewCount is Count -1,
copypred(PredHead, CopyPredHead),
retract(( CopyPredHead :- FoundBody)), !,
getconjofclause(PredHead,
NewCount, ConjunctNum, Conjunct),
asserta((CopyPredHead:- FoundBody)).
getconjofclause( . . . . . . true) :-
printstring("Warning clause index out of bounds").
grabconjunct((Conjunct, _), 1, Conjunct) :- !.
grabconjunct(Conjunct, 1, Conjunct) :- !.
grabconjunct((_, Rest), Count, Conjunct) :-
NewCount is Count - I,
grabconjunct(Rest, NewCount, Conjunct), !.
grabconjunct( . . . . true) :-
printstring("Warning conjunct index out of bounds").
/*remove Clauses */
removeclause(PredHead, 1) :-
retract((PredHead : - _ ) ) , !.
removeclause(PredHead, Count) :-
NewCount is Count -1,
copypred(PredHead, CopyPredHead),
retract(( CopyPredHead :- FoundBody)), t,
removeclause(PredHead, NewCount),
asserta((CopyPredHead:- FoundBody)).
removeclause(_, _) :-
printstring("Warning clause index out of bounds").
/* Remove Conjuncts */
removeconjofclause(PredHead, 1, ConjunctNum) :-
retract((PredHead :- FoundBody)), !,
removeconjunct(FoundBody, ConjunctNum, NewBody),
asserta((PredHead :- NewBody)).
copypred(PredHead, CopyPredHead),
retract(( CopyPredHead :- FoundBody)), I,
removeconjofclause(PredHead, NewCount, ConjunctNum),
asserta((CopyPredHead:- FoundBody)).
removeconjofclause( . . . . . ) :-
printstring("Warning clause index out of bounds").
removeconjunct(First, 1, true) :- !.
removeeonjunct(One, _, One) :-
printstring("Warning conjunct index out of bounds").
/*Replace Clauses*/
replaceclause( . . . . . ) :-
printstring("Warning clause index out of bounds").
/* replace conjuncts */
retract((PredHead :- FoundBody)), !,
replaceconjunct(FoundBody, ConjunctNum, Conjunct, NewBody),
asserta((PredHead :- NewBody)).
replaceeonjofclause(. . . . . . . ) :-
printstring("Warning clause index out of bounds").
replaceconjunct(One . . . . . One) :-
printstring("Warning conjunct index out of bounds").
/* Exchange Clauses*/
/* There are two recursive steps to this predicate: l) get the first
clause; 2) get the second clause placing the first in its place. Upon
returning from the second recursive step place the second clause
in place of the first.
*/
Altering and applying predicates 73
exchangeclause(PredHead, 1, ToClauseNum) :-
PredHead =.. [PredNamelArgs],
retract(( PredHead :- FoundBody)), !,
NewToCount is ToClauseNum -1,
replaceelauseandreturn(PredName, NewToCount,
larnbda(Args, FoundBody), lambda(RArgs, RBody)),
NPredHead =.. [PredNamelRArgs],
asserta((NPredHead:- RBody)).
exchangeclause(. . . . . ) :-
printstring("Warning FromClause index out of bounds").
replaceclauseandreturn(PredName, 1,
lambda(Args, Body), lambda(RArgs, RBody)) :-
PredHead =.. [PredNamelArgs],
constructargs(Args, RArgs),
CopyPredHead =.. [PredNamelRArgs],
retract(( CopyPredHead :- RBody)), t,
asserta((PredHead:- Body)).
/* Exchange Conjuncts */
/* There are four recursive steps to this predicate: 1) get the first
clause; 2) get the conjunct of the first clause; 3) get the second
clause; 4) get the conjunct of the second clause placing the first
conjunct in its place and asserting it. Return the second conjunct
and on recursive returns place the second conjunct in place of the
first conjunct and assert the newly created clause.
*/
exchangeclause(. . . . . . . . . ) :-
printstring("Warning FromClause index out of bounds").
N T i s T - 1,
exconjandreturn(PredHead, NewCount, Rest, Return,
ToClause, ToConj, NT),
!.
/* Pattern Matching */
About the Author--H. JUSTIN COVEN received a B.S. Degree in Mathematics from the University of
Arizona in 1983, an M.S. degree in Computer Science from the University of Arizona in 1985 and a Ph.D.
in Computer Science from Arizona State University in 1991. He then joined the faculty of Bellarmine
College, where he is now Assistant Professor in the Department of Computer Science. His research
activities center around the development of reflective language facilities that enable programming
languages to manipulate and access their internal structures. Further research activity will include the
usage of these facilities to develop intelligent programs that reason about themselves. Dr Coven is a
member of the Association for Computing Machinery, The Cognitive Science Society, the American
Association for Artificial Intelligence and Computer Professionals for Social Responsibility.