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 SICStus Prolog uses a choicepoint, 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 choicepoint 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, SICStus Prolog improves upon this simple model by recognizing
certain contexts in which choicepoints
can be avoided, or are no longer needed.
The Prolog cut (‘!’) works by removing choicepoints, disabling the potential backtracking they represented. A choicepoint 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 choicepoints on the stack that could allow backtracking to the clause. Thus, the existence of a single choicepoint on the stack can disable reclamation of retracted clauses for the procedure whose call created the choicepoint. Space is recovered only when the choicepoint 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 choicepoint
will be created by retract/1
. While executing “<do more stuff
without backtracking>”, that choicepoint will remain on the stack,
making it impossible to reclaim the retracted Clause. Such
choicepoints can also disable tail recursion optimization. If not cut
away, the choicepoint can also lead to runaway retraction on the
unexpected failure of a subsequent goal. This can be avoided by
simply cutting away the choicepoint 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.