4.12.5.1 A Note on Efficient Use of 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.


Send feedback on this subject.