next up previous contents index
Next: Execution State Up: Standard Predicates Previous: Information about the State   Contents   Index


Modification of the Database

XSB provides an array of features for modifying the dynamic database. Using assert/1, clauses can be asserted using first-argument indexing in a manner that is now standard to Prolog implementations. While this is the default behavior for XSB, other behavior can be specified using the (executable) directives index/3 and index/2. For instance, dynamic clauses can be declared to have multiple or joint indexes, while this indexing can be either hash-based as is typical in Prolog systems or based on tries. No matter what kind of indexing is used, space is dynamically allocated when a new clause is asserted and, unless specified otherwise, released when it is retracted. Furthermore, the size of any index table expands dynamically as clauses are asserted.

Consider first dynamic predicates that use traditional hash-based indexing. XSB asserts WAM code for such clauses, leading to execution times similar to compiled code for unit and binary clauses. Furthermore, tabling can be used with a dynamic predicate by explicitly declaring a predicate to be both dynamic and tabled. For clauses that are asserted as WAM code, the ``immediate semantics'' of dynamic predicates is used, not the so-called ``logical semantics'' of assert/retract [27]. This means that significant care must be taken when modifying the definition of a predicate which is currently being executed. Notice that this makes some operations difficult. For example, one might try to retract from dynamically asserted predicates, p/1 and q/1, exactly their intersection, by issuing the following query:

:- p(X), q(X), retract(p(X)), retract(q(X)), fail.
Neither retract/1 nor retractall/1 support this behavior, due to their techniques for space reclamation. One alternative is to use findall/3 to collect the intersection first, before retracting. Another is to use the predicates retract_nr/1 and reclaim_space/1, described below.

Asserting clauses as WAM code might be considerably slow for some applications. To remedy this, XSB provides an alternative to assert/1 which implements assert's functionality using the trie-based tabling data structures [33]. Though trie-based dynamic code can be created (and usually executed) significantly faster than using assert/1, users of the following predicates should be aware that trie-based assert can be used only for unit clauses where a relation is viewed as a set, and where the order of the facts is not important.

XSB does not at this time fully support dynamic predicates defined within compiled code. The only way to generate dynamic code is by explicitly asserting it, or by using the standard predicate load_dyn/1 to read clauses from a file and assert them (see the section Asserting Dynamic Code in Volume 2). There is a dynamic/1 predicate (see page [*]) that declares a predicate within the system so that if the predicate is called when no clauses are presently defining it, the call will quietly fail instead of issuing an ``Undefined predicate'' error message.

assert(+Clause)

adds a dynamic clause, Clause, to the database. Clause must be of one of the forms: Head or Head :- Body. Note that because of the precedence of :-/2, using the second form requires an extra set of parentheses: assert((Head :- Body)). Default: first-argument indexing.

asserta(+Clause)

If the index specification for the preicate is not tries, this predicate adds a dynamic clause, Clause, to the database before any other clauses for the same predicate currently in the database. If the index specification for the predicate is trie, the clause is asserted arbitrarily within the trie, and a warning message sent to stderr.

assertz(+Clause)

If the index specification for the predicate is not tries, this predicate adds a dynamic clause, Clause, to the database after any other clauses for the same predicate currently in the database. If the index specification for the predicate is trie, the clause is asserted arbitrarily within the trie, and a warning message sent to stderr.

retract(+Clause)

removes through backtracking all clauses in the database that match with Clause. Clause must be of one of the forms: Head or Head :- Body. Note, that because of the precedence of :-/2, using the second form requires an extra set of parentheses: retract((Head :- Body)). Space is reclaimed when a clause is retracted.

retractall(+Head)

removes every clause in the database whose head matches with Head. The predicate whose clauses have been retracted retains the dynamic property (contrast this behavior with that of predicates abolish/[1,2] below). Predicate retractall/1 is determinate and always succeeds. The term Head is not further instantiated by this call.

abolish(+PredSpec)

Removes the definition of the specified predicate. PredSpec is of the form Pred/Arity. Everything about the abolished predicate is completely forgotten by the system (including the dynamic property). There is also an abolish/2 which takes Pred and Arity as its two arguments.

clause(+Head,?Body)

Returns through backtracking all dynamic clauses in the database whose head matches Head and Body matches Body. For facts the Body is true.

retract_nr(+Clause)

Performs just as retract/1 does, except that it does not reclaim the space used by the retracted clause. This is provided to allow programmers to modify dynamic clauses while executing them (a practice that is discouraged.) For example, to retract an intersection, as described above, one could do:
:- p(X), q(X), retract_nr(p(X)), retract_nr(q(X)), fail.
In order to reclaim space after using retract_nr/1, see reclaim_space/1 below. Predicate retract_nr/1 is not a standard predicate and must be imported from module assert. retract_nr/1 is provided for (partial) compatibility with the retract/1 predicate of SB-Prolog.

reclaim_space(+Head)

Runs through the dynamic code for the predicate indicated by Head, and reclaims space for any clauses that have been deleted from that predicate by retract_nr/1. This cannot safely be used when execution is still within some invocation of the specified predicate, or will backtrack into such a scope. To complete our example of retracting the intersection of dynamic predicates:
:- p(X), q(X), retract_nr(p(X)), retract_nr(q(X)), fail ;
reclaim_space(p(_)), reclaim_space(q(_)).
would do the trick. Notice that the reclaim_space calls must be made after execution has completely failed out of choice points for q(X) and p(X). Predicate reclaim_space/1 is not standard but must be imported from module assert. As with retract_nr, the use of this predicate is discouraged; it is provided for (partial) compatibility with SB-Prolog.

index(+PredSpec, +IndexSpec)

In general, XSB supports hash-based indexing on alternate arguments or combinations of arguments, along with trie-based indexing. The availability of various kinds of indexing depends on whether code is static (e.g. compiled) or dynamic (e.g. asserted or loaded with load_dyn/1). The executable directive index/2 does not re-index an already existing predicate but takes effect only if the program store contains no clauses for PredSpec. Index directives can be given to the compiler as part of source code or executed during program execution (analogously to op/3).

dynamic(+PredSpec)

is an executable predicate which converts a predicate specified as (Predicate/Arity) to a dynamic predicate. If Predicate is not previously defined, it will be initialized to empty (so that calls to it quietly fail, instead of issuing ``Undefined predicate'' error messages.) If the predicate is previously defined and dynamic, dynamic/1 is a noop. If previously defined as compiled, Predicate will be converted to dynamic, which means that clauses can be added, although the compiled portion cannot be manipulated. Note that dynamic/1 can be used like a compiler directive, since it will be passed through to be executed when the module is loaded. Note, however, that the semantics is different from that of the standard [20] when the file contains clauses defining the so-specified predicate.

table(+PredSpec)

is an executable predicate, where PredSpec is a predicate specification for a dynamic predicate. (This is also a compiler directive when PredSpec specifies a compiled predicate. See the section of this manual on compiler directives.) This predicate declares a dynamic predicate to be tabled. It simply saves information to be used at the time of assert and so it must be called before any clauses are asserted into the specified predicate in order for the predicate to be tabled.


next up previous contents index
Next: Execution State Up: Standard Predicates Previous: Information about the State   Contents   Index
Baoqiu Cui
2000-04-23