Imagine we have the familytree
module below (simple example) :
:- module(familytree, [
father/2,
mother/2,
%[...]
]).
father(X,Y) :- male(X),parent(X,Y).
father(unknown, _) :- male(unknown).
mother(X,Y) :- female(X),parent(X,Y).
mother(unknown, _) :- female(unknown).
sister(X,Y) :- female(X),parent(Z,X),parent(Z,Y), X \= Y.
%[... other relation predicates ... ]
I want to use this module predicates with different "dbs", for examples with :
:- module(familytree_xyz, []).
male(james).
male(fred).
male(mike).
female(betty).
female(sandra).
parent(james, fred).
parent(betty, fred).
Or :
:- module(familytree_simpson, []).
male(homer).
male(bart).
female(marge).
female(lisa).
parent(homer, bart).
%[...]
I need :
- to choose db on runtime, not on compilation.
- to use one or more dbs in same time.
- to extend db, for eg. create a “familytree_simpson_extended” db module with other Simpson family members extending “familytree_simpson” db module (see above example)
- to be swi-prolog compliant.
For now, I tried to play with term_expansion/2
, discontiguous/1
, multifile/1
, dynamic/1
and thread_local/1
directives, but :
term_expansion/2
seems only usable on compile time,discontiguous/1
,multifile/1
, not adapted,- dynamic dbs in prolog are seen as an “Evil” practice, however lot of packages and libraries use its (
pengines
,broadcast
module,http
lib, for examples). thread_local/1
is not very documented and seems not often used in prolog source code (swi-prolog).
With playing with dynamic predicate, I update previous code as follow :
%familytree.pl
:- module(familytree, [
familytree_cleanup_db/0,
familytree_use_db/1,
%[... previous declarations ...]
]).
dynamic male/1, female/1, parent/2.
familytree_cleanup_db :-
retractall(male/1),
retractall(female/1),
retractall(parent/2).
familytree_use_db(ModuleName) :-
assert(male(X) :- ModuleName:male(X)),
assert(female(X) :- ModuleName:female(X)),
assert(parent(X,Y) :- ModuleName:parent(X,Y)).
%[... previous predicates ...]
And :
%main.pl
% use familytree tool predicates
:- use_module(familytree).
%load all familytree dbs at compile time.
:- use_module(familytree_xyz).
:- use_module(familytree_simpson).
:- use_module(familytree_simpson_extended).
main_xyz:-
familytree_cleanup_db,
familytree_use_db(familytree_xyz),
process.
main_simpson_all :-
familytree_cleanup_db,
familytree_use_db(familytree_simpson),
familytree_use_db(familytree_simpson_extended),
process.
process :-
findall(X, father(X,_), Xs),
write(Xs).
And it's ok to use with different db as follow :
?- main_simpson_all.
[homer,homer,abraham]
true.
?- main_xyz.
[james]
true.
So, sorry for the length of the post. Questions :
-
What are the criteria, pros/cons to consider with this dynamic predicates solution ? is it a good solution ?
-
What are the best practice / specific design pattern for prolog to do that in a clean / robust code ?**
-
What's about using
thread_local/1
insteaddynamic/1
and encapsulate call to new thread to avoid cleanup db?
Aucun commentaire:
Enregistrer un commentaire