SWI-Prolog offers several ways to store data in globally accessible memory, i.e., outside the Prolog stacks. Data stored this way notably does not change on backtracking. Typically it is a bad idea to use any of the predicates in this section for realising global variables that can be assigned to. Typically, first consider representing data processed by your program as terms passed around as predicate arguments. If you need to reason over multiple solutions to a goal, consider findall/3, aggregate/3 and related predicates.
Nevertheless, there are scenarios where storing data outside the Prolog stacks is a good option. Below are the main options for storing data:
Dynamic predicates can be wrapped using library
to maintain a backup of the data on disk. Dynamic predicates come in two
flavours, shared between threads and local to each
thread. The latter version is created using the directive
According to the ISO standard, abolish/1
can only be applied to dynamic procedures. This is odd, as for dealing
with dynamic procedures there is already retract/1
predicate was introduced in DEC-10 Prolog precisely for dealing with
static procedures. In SWI-Prolog, abolish/1
works on static procedures, unless the Prolog flag iso
is set to
It is advised to use retractall/1 for erasing all clauses of a dynamic predicate.
abolish(Name/Arity). The predicate abolish/2 conforms to the Edinburgh standard, while abolish/1 is ISO compliant.
copy_predicate_clauses(From, To) :- head(From, MF:FromHead), head(To, MT:ToHead), FromHead =.. [_|Args], ToHead =.. [_|Args], forall(clause(MF:FromHead, Body), assertz(MT:ToHead, Body)). head(From, M:Head) :- strip_module(From, M, Name/Arity), functor(Head, Name, Arity).
userand in normal modules to redefine any system predicate. If the system definition is redefined in module
user, the new definition is the default definition for all sub-modules. Otherwise the redefinition is local to the module. The system definition remains in the module
Redefining system predicate facilitates the definition of compatibility packages. Use in other contexts is discouraged.
beeon backtracking despite the fact that
beeis already retracted.68Example by Jan Burse.
:- dynamic insect/1. insect(ant). insect(bee). ?- ( retract(insect(I)), writeln(I), retract(insect(bee)), fail ; true ). ant ; bee.
If multiple threads start a retract on the same predicate at the same
time their notion of the entry generation is adjusted such that
they do not retract the same first clause. This implies that, if
multiple threads use
once(retract(Term)), no two threads
will retract the same clause. Note that on backtracking over retract/1,
multiple threads may retract the same clause as both threads respect the
logical update view.
recorda(Key, Term, _).
recordz(Key, Term, _).
current_key(Key), recorded(Key, Value, Reference)
recorded(Key, Value, _).
The predicate flag/3 is the oldest way to store global non-backtrackable data in SWI-Prolog. Flags are global and shared by all threads. Their value is limited to atoms, small (64-bit) integers and floating point numbers. Flags are thread-safe. The flags described in this section must not be confused with Prolog flags described in section 2.11.
next_id(Id) :- flag(my_id, Id, Id+1).
Tries (also called digital tree, radix tree or prefix tree maintain a mapping between a variant of a term (see =@=/2) and a value. They have been introduced in SWI-Prolog 7.3.21 as part of the implementation of tabling. The current implementation is rather immature. In particular, the following limitations currently apply:
We give the definition of these predicates for reference and debugging tabled predicates. Future versions are likely to get a more stable and safer implementation. The API to tries should not be considered stable.
Traditionally, Prolog systems used the immediate update view: new clauses became visible to predicates backtracking over dynamic predicates immediately, and retracted clauses became invisible immediately.
Starting with SWI-Prolog 3.3.0 we adhere to the logical update view, where backtrackable predicates that enter the definition of a predicate will not see any changes (either caused by assert/1 or retract/1) to the predicate. This view is the ISO standard, the most commonly used and the most `safe'.71For example, using the immediate update view, no call to a dynamic predicate is deterministic. Logical updates are realised by keeping reference counts on predicates and generation information on clauses. Each change to the database causes an increment of the generation of the database. Each goal is tagged with the generation in which it was started. Each clause is flagged with the generation it was created in as well as the generation it was erased from. Only clauses with a `created' ... `erased' interval that encloses the generation of the current goal are considered visible.
The indexing capabilities of SWI-Prolog are described in section 2.18. Summarizing, SWI-Prolog creates indexes for any applicable argument, but only on one argument, and does not index on arguments of compound terms. The predicates below provide building blocks to circumvent the limitations of the current indexing system.
Programs that aim at portability should consider using term_hash/2 and term_hash/4 to design their database such that indexing on constant or functor (name/arity reference) on the first argument is sufficient.
This predicate may be used to build hash tables as well as to exploit argument indexing to find complex terms more quickly.
The hash key does not rely on temporary information like addresses of atoms and may be assumed constant over different invocations and versions of SWI-Prolog.72Last change: version 5.10.4 Hashes differ between big and little endian machines. The term_hash/2 predicate is cycle-safe.bugAll arguments that (indirectly) lead to a cycle have the same hash key.
HashKey is in the range [0 ...Range-1]. Range must be in the range [1 ... 2147483647]
This predicate raises an exception when trying to compute the hash on a cyclic term or attributed term. Attributed terms are not handled because subsumes_chk/2 is not considered well defined for attributed terms. Cyclic terms are not supported because this would require establishing a canonical cycle. That is, given A=[a|A] and B=[a,a|B], A and B should produce the same hash. This is not (yet) implemented.
This hash was developed for lookup of solutions to a goal stored in a table. By using a cryptographic hash, heuristic algorithms can often ignore the possibility of hash collisions and thus avoid storing the goal term itself as well as testing using =@=/2.