1

There is something about retract/1 that doesn't make sense to me.

According to ISO/IEC 13211-1:1995:

8.9.3 retract/1

8.9.3.1 Description

retract(Clause) is true iff the database contains at least one dynamic procedure with a clause Clause which unifies with Head :- Body.

Procedurally, retract(Clause) is executed as follows:

a) If Clause unifies with ':-'(Head, Body), then proceeds to 8.9.3.1 c,

b) Else unifies Head with Clause and true with Body,

c) Searches sequentially through each dynamic user-defined procedure in the database and creates a list L of all the terms clause(H, B) such that 1) the database contains a clause whose head can be converted to a term H (7.6.3), and whose body can be converted to a term B (7.6.4), and 2) H unifies with Head, and 3) B unifies with Body.

d) If a non-empty list is found, then proceeds to 8.9.3.1 f,

e) Else the goal fails.

f) Chooses the first element of the list L, removes the clause corresponding to it from the database, and the goal succeeds.

g) If all the elements of list L have been chosen, then the goal fails.

h) Else chooses the first element of the list L which has not already been chosen, removes the clause, if it exists, corresponding to it from the database and the goal succeeds.

retract(Clause) is re-executable. On backtracking, continue at 8.9.3.1 g. [...]

"If it exists"? How could it be that it does not exist anymore upon re-execution?

The database update semantics suggest that "it" always exists:

7.5.4 A logical database update

Any change in the database that occurs as a result of executing a goal (for example, when the activator of a subgoal is a call of assertz/1 or retract/1) shall affect only an activation whose execution begins afterwards. This change shall not affect any activation that is currently being executed.

NOTE — Thus the database is frozen during the execution of a goal, and the list of clauses defining a predication is fixed at the moment of its execution (see 7.7.7 e).

Below, I tried using retract(f(3)) to make clause f(3) vanish before the re-execution of a prior retract(f(X)):

?- abolish(f/1), maplist(assertz,[f(1),f(2),f(3)]).
true. % setup complete

?- retract(f(X)), ( X = 2 -> retract(f(3)) ; true ).
   X = 1
;  X = 2
;  X = 3. % <----------------^^^^^^^^^^^^^

... but, alas, I failed: SICStus Prolog, GNU Prolog and SWI-Prolog gave the same (above) answers.

So why use the phrase "if it exists" in this context? To me it's redundant. And puzzling... help please!

repeat
  • 18,496
  • 4
  • 54
  • 166
  • 2
    Nevertheless, if there are multiple retracts, on of them is the first to delete. And thus what happens to the next one? It wants to delete as well, but cannot. – false Feb 27 '20 at 23:53
  • @false Replace `retract(f(3))` with `abolish(f/1)` and "SWI stable-current" crashes... – repeat Feb 28 '20 at 08:32
  • @false. Does the standard disallow the answer sequence `X = 1 ; X = 2.` ? – repeat Feb 28 '20 at 08:50
  • Of course it disallows this sequence. Imagine retract/1 is implemented with a findall/3 in front. – false Feb 28 '20 at 19:53
  • 1
    @false. Ahhh. So it's a snapshot for the answers of retract/1, but that snapshot cannot predict the *actual* state of the database when deletion time comes. Hence the "if it exists". Makes sense. – repeat Feb 29 '20 at 00:44
  • 2
    abolish(f/1) and "SWI stable-current" crashes... Confirmed. Runs fine in development (8.1.x) series. – Jan Wielemaker Mar 01 '20 at 14:32
  • 1
    @false and by default to repeat. Could one you post an answer to this so others know it has an answer and also appears to have an accepted answer based on the comments. – Guy Coder Mar 05 '20 at 15:24

0 Answers0