Prolog modules don't provide a sensible solution for the design pattern you're trying to implement. This design pattern is sometimes referred as the "many worlds" pattern. But you can do it easily using in alternative Logtalk objects (you can run Logtalk with most Prolog compilers including SWI-Prolog).
First, define a root object declaring your database predicates:
:- object(database).
:- public([predicate1/2, predicate2/2]).
:- dynamic([predicate1/2, predicate2/2]).
:- end_object.
You can have any number of database objects extending this object. To associate a file with each individual database/object, you can simple use an include/1
directive to load the contents of the files into the respective objects when these are loaded. For example:
:- object(db1, extends(database)).
:- include('db1.db').
:- end_object.
:- object(db2, extends(database)).
:- include('db2.db').
:- end_object.
You can also easily create dynamic databases:
...,
% ensure the corresponding file exists
open(write, 'db42.db', Stream),
close(Stream),
% create the dynamic database object
create_object(db42, [extends(database)] [include('db42.db')], []),
...
You also want to be able to make inferences using the different databases:
Then, I defined in a third file predicates.pl several clauses which
make use of clauses in the previous databases such as
testPredicate(A,B) :- predicate1(A,B), predicate2(A,B).
You can do it easily by defining the testPredicate/2
predicate in the root object, which becomes:
:- object(database).
:- public([predicate1/2, predicate2/2]).
:- public(testPredicate/2).
testPredicate(A,B) :-
::predicate1(A,B),
::predicate2(A,B).
:- end_object.
The ::/1
is Logtalk's message to self control construct. This means that in a goal such as:
?- db1::testPredicate(A,B).
the predicate1/2
and predicate2/2
will be called in db1
while in the goal:
?- db2::testPredicate(A,B).
the predicate1/2
and predicate2/2
will be called in db2
. To modify a database dynamic predicates, simply use the assert and retract messages to the database objects. For example:
?- db42::assertz(predicate1(foo,bar)).
...
Finally, you want to persist the database dynamic predicates. We can e.g add a predicate to the root object that saves all databases to the respective files. For example (assuming the database predicate clauses are facts):
:- public(save/0).
save :-
this(This),
forall(
extends_object(Database, This),
save(This)
).
save(Database) :-
atom_concat(Database, '.db', File),
open(File, write, Stream),
save_predicates(Database, Stream),
close(Stream).
save_predicates(Database, Stream) :-
current_predicate(Functor/Arity),
functor(Template, Functor, Arity),
predicate_property(Template, (dynamic)),
write_canonical(Stream, (:- dynamic(Functor/Arity))), write('.\n),
Database::clause(Template, true),
write_canonical(Stream, Template), write('.\n),
fail.
save_predicates(_, _).
To save all databases, you simply call the goal database::save
. Note that the sketched solution is fully portable. you can use with any of the Logtalk supported Prolog compilers.
db1_predicate1
, etc. Or the database name is an argument to the predicate and the predicates do have the same name. Hard to tell here since your use case isn't clear in detail. – Roadster:-( head, body )
. – Roadsterassertz(':-'(foo(X,Y), (...))).
. – RoadsterdataBaseN.pl
, I will also dynamically create the corresponding predicate version inpredicates.pl
:testPredicate(A,B) :- dataBaseN:predicate1(A,B), dataBaseN:predicate2(A,B)
. It seems rather verbose but at least It should work. – Claudette