retract/1
WARNING: retract/1
is a nondeterminate procedure. Thus, we can use
| ?- retract((foo(X) :- Body)), fail.
to retract all clauses for foo/1
. A nondeterminate procedure
in Quintus Prolog uses a choice point, a data structure kept
on an internal stack, to implement backtracking. This applies to
user-defined procedures as well as to built-in and library procedures.
In a simple model,
a choice point is created for each call to a nondeterminate procedure,
and is deleted on determinate success or failure of that call, when
backtracking is no longer possible.
In fact, Quintus Prolog improves upon this simple model by recognizing
certain contexts in which choice points
can be avoided, or are no longer needed.
The Prolog cut (!
) works by removing choice points, disabling
the potential backtracking they represented. A choice point
can thus be viewed as an "outstanding call", and a
cut as deleting outstanding calls.
To avoid leaving inconsistencies between the Prolog database and outstanding calls, a retracted clause is reclaimed only when the system determines that there are no choice points on the stack that could allow backtracking to the clause. Thus, the existence of a single choice point on the stack can disable reclamation of retracted clauses for the procedure whose call created the choice point. Space is recovered only when the choice point is deleted.
Often retract/1
is used determinately; for example, to retract a single
clause, as in
| ?- <do some stuff> retract(Clause), <do more stuff without backtracking>.
No backtracking by retract/1
is intended. Nonetheless,
if Clause may match more than one clause in its procedure, a choice point
will be created by retract/1
. While
executing "<do more stuff without backtracking>", that choice point will
remain on the stack, making it impossible to reclaim the retracted Clause.
Such choice points can also disable tail recursion optimization.
If not cut away, the choice point
can also lead to runaway retraction on the unexpected failure of a
subsequent goal. This can be avoided by simply cutting away the choice
point with an explicit cut
or a local cut (->
).
Thus, in the previous example, it is preferable to write either
| ?- <do some stuff> retract(Clause), !, <do more stuff without backtracking>.
or
| ?- <do some stuff> ( retract(Clause) -> true ), <do more stuff without backtracking>.
This will reduce stack size and allow the earliest possible reclamation
of retracted clauses. Alternatively, you could use retract_first/1
,
defined in library(retract)
.