ok@quintus.UUCP (Richard A. O'Keefe) (03/09/88)
There seems to be some confusion about what the command retractall(Head) does/should do. There are apparently two families: The "Head" family. In this family, retractall(Head) :- clause(Head, _Dont_Care, Ref), erase(Ref), fail ; true. That is, it retracts all the clauses whose HEADS match Head. Quintus Prolog uses this definition, which we copied from C Prolog, which got it from NU7 PDP-11 Prolog, which got it from an early version of DEC-10 Prolog. NU Prolog (from Melbourne) also belongs to this family. ESI Prolog basically belongs to this family, but beware of trying to retract clauses from the predicate (/)/2! The "Clause" family. In this family, *retractall(Clause) :- retract(Clause), fail ; true. AAIS Prolog belongs to this family, but then the AAIS manual frankly calls it "a new dialect" and says "Edinburgh Mode ... does not make AAIS Prolog 100% compatible". Since assert(Clause,Ref), erase(Ref) may erase some other clause entirely, this is a true statement! I do not know which other Prologs belong to this family. Why have retractall/1 at all? There are two reasons. The first is that it is usefully different from abolish/2 or abolish/1, and the second is that there is no portable way of defining it. Difference from abolish/[1,2]. What's the difference between abolish(p, 2) or abolish(p/2) and retractall(p(_,_))? Very simple. abolish/[1,2] make it as if the predicate had never existed. All the information which the system has about an abolished predicate is discarded. Spy-points, dynamic/static flag, any other information, all of it goes. abolish/[1,2] make a predicate completely undefined. retractall(Head) can only affect dynamic predicates (in those systems which make a distinction between static and dynamic code; note that this is not intrinsically the same as the distinction between compiled and interpreted). It removes the clauses whose heads match Head, but that's all; any other clauses for the same predicate remain intact, any spy-points or other debugging information remain unchanged, any other information (such as which file(s) the predicate came from) remains, even if the last clause goes. For example, if you have a program which looks like :- dynamic p/2. go :- {initialise} {process} {terminate}. and either {initialise} or {terminate} clears out p/2, the thing to use is retractall(p(_,_)) rather than abolish(p,2), because retractall will just remove the clauses, while abolish will make p/2 undefined. No portable definition using more basic operations. Why do I say that there is no portable way of defining retractall/1? Well, the definition I gave above won't work in a Prolog system which lacks clause/3, or which, like AAIS Prolog, may erase the wrong clause. The next obvious thing to try is retractall(Head) :- retract((Head :- _Body)), fail ; true. but that won't work in some Prolog systems, which would see this call to retract/1 as retract((Head :- call(Body))). Neither will it work in some other Prolog systems, where unit clauses Head are not identified with Head:-true. (This is not the least of the reasons for making retractall(Head) operate on heads rather than whole clauses.) Nor yet will it work in AAIS Prolog, where one has to write retract((Head :- ... _Body)) Given that the Head version is a useful operation which cannot be defined portably in terms of other operations, and that the Clause version is trivially easy to define it you want it, I think it's clear which version should be provided by Prolog vendors (in the absence of some method clearly superior to both).