Many thanks both – is very helpful. I’m still struggling to bend modules to my will.
Ideally I’d have a common set of rules that see an independent set of rules (>1000) loaded into a thread’s query. Let’s sat we want a set of rules shared between many threads:
% thread_rules.pl
rule(X) :- fact(X).
we have the problem that rule/1 needs to find fact/1 (to be later defined by thread).
The facts can’t be entered into user: or thread_rules: because it would interfere with parallel threads.
I think what is needed is to achieve something like:
thread1:rule(X) :- thread1:fact(X).
that is, rules that have references to facts must be duplicated per thread. (The ugly alternative
is to pass the set of facts as parameter to rule(FACTS, X)
… and its dependency predicates, which may be many.
What seems to work (sort of) is using load_files.
% thread_setup.pl
% Define: thread1:rule(X) :- thread1:fact(X)
thread1:setup:-
thread1:load_files(thread_rules, [module(thread1), register(false)]),
print("Setup thread1 rules").
% Define: thread2:rule(X) :- thread1:fact(X)
thread2:setup :-
thread2:load_files(thread_rules, [module(thread2), register(false)]),
print("Setup thread2 rules").
% Define facts for testing
thread1:fact(1).
thread2:fact(2).
Which I can use as:
%example.pl -- run as cat example.pl | swipl
load_files(thread_setup, []).
thread1:setup. % Prints setup thread1 rules
thread2:setup. % Prints setup thread2 rules
findall(X, thread2:rule(X), Y). % --> [1]
findall(X, thread1:rule(X), Y). % undefine procedure thread1:rule/1
This works great for the findall(X, thread2:rule(X), Y).
. It matches thread2:fact(2), but
for the second query (the last line) thread1:rule doesn’t exist! (ERROR: Undefined procedure: thread1:rule/1).
I’m guessing that the second call to load_files unloaded whatever was loaded in the first call.
(I was hoping register(false) would avoid this).
So…
-
Is there a better way to attach a common set of rule sourcefiles to per-thread facts? Or perhaps somehow copy the contents of a module into another and rebind the references to that facts to the current module? (I briefly tried import/1, but couldn’t make it work).
-
Does my problem mean that load_files is not thread safe? This docs mention that
"Reloading a previously loaded file is safe, ". Is it so? In my case we’ve had the
effect of abolish/unload_file (since thread1:rule has disappeared). The docs
say abolish/unload_file are not thread safe.
-
To get my example to work, I had to place
thread1:fact(1).
thread2:fact(2).
into thread_setup.pl. If I move them to setup.pl
% Define facts for testing
thread1:fact(1).
thread2:fact(2).
load_files(thread_setup, []).
thread1:setup.
thread2:setup.
findall(X, thread2:rule(X), Y).
findall(X, thread1:rule(X), Y).
… thread2:rule(X) finds thread2:fact/1 is undefined. Why?
Thanks in advance,