| % |
| % This file contains working code for backtrackable updates |
| % It works with many different Prologs, and is the conceptual kernel |
| % of all my TR prototypes. |
| % |
| % The code implements strong inserts and strong deletes. That is, the |
| % update ins(p) inserts the atom p into the database, but if p is |
| % already there, then ins(p) fails. Likewise, the update del(p) deletes |
| % atom p from the database, but if p is not there to begin with, then |
| % del(p) fails. |
| % |
| % The code is based on insert and delete tags. The first time that |
| % ins(p) is executed, it adds the atom inserted(p) to the database. |
| % This atom remains in the database until ins(p) is backtracked. |
| % Subsequently, if del(p) is executed, then the atom deleted(p) is added |
| % to the database; and if ins(p) is executed, then the atom deleted(p) |
| % is removed from the database. This technique prevents the Prolog |
| % database from being corrupted when backtracking through updates. |
| % |
| % The atom db(p) determines whether p is true in the current database |
| % state. It returns true iff inserted(p) is in the database and deleted(p) |
| % is not. |
| % |
| :- export ins/1, asrt/1, del/1, db/1, empty/1, updat/1. |
| % Atom P is in the database if it has been inserted and not deleted. |
| % |
| db(P) :- modifiable(P), inserted(P), not(deleted(P)). |
empty(P) :- modifiable(P), not(db(P)).
updat(P) :- modifiable(P).
| % Initial inserts are a special case. To insert P for the first time. |
| % add the atom inserted(P) to the database. The predicate undo_ins1 |
| % removes this atom during backtracking. |
| % |
| % To undo an initial insert, remove the inserted fact. |
| % |
| undo_ins1(P). |
| undo_ins1(P) :- retract(inserted(P)), !, fail. |
| % For all subsequent inserts, remove the atom deleted(P) from the |
| % database. The predicate undo_ins2 puts the atom back during |
| % backtracking. |
| % |
| ins(P) :- modifiable(P), |
| deleted(P), |
| retract(deleted(P)), |
| undo_ins2(P). |
|
| % To undo a subsequent insert, put the delete tag back. |
| % |
| undo_ins2(P). |
| undo_ins2(P) :- asserta(deleted(P)), !, fail. |
| % To delete P, put the atom deleted(P) into the database. The |
| % predicate undo_del removes this atom during backtracking. |
| % |
| del(P) :- modifiable(P), |
| inserted(P), |
| not(deleted(P)), |
| assert(deleted(P)), |
| undo_del(P). |
| % To undo a deletion, remove the delete tag. |
| % |
| undo_del(P). |
| undo_del(P) :- retract(deleted(P)), !, fail. |
| asrt(P) :- assert(modifiable(P)). |
| % The following dummy rules let Prolog know that the predicates |
| % inserted/1 and deleted/1 are defined. |
| % |
| inserted(dummy) :- fail. |
| deleted(dummy) :- fail. |
| modifiable(dummy) :- fail. |
| empty(dummy) :- fail. |