[EDIT] I figured it out… so changing this to a “nice to know” instead of “help” and adding the solution to the bottom.
(SWI 8.2.1 64b) The context for what I’m trying to do is as follows: let’s say that you have a module for managing a database of dynamic predicates. But you want the dynamic predicates to be asserted in another module. For instance, you might have more than one module making use of the same common database management routines, but you don’t want the actual database predicates to get all mixed up.
My first go at this was as follows:
% the database manager module :- module( dbmanager, [ addfu/1, getfu/1 ]). :- multifile fu/1. % doesn't work :- module_transparent addfu/1. addfu(B):- asserta(fu(B)). delfu(B):- retract(fu(B)). getfu(B):- fu(B).
% the module where the database predicates should be asserted in :- module(localdb,). :- dynamic(fu/1). :- use_module(dbmanager). :- addfu(bar). :- getfu(B), writeln(B).
This works fine for adding the database predicates (i.e. for
addfu/1), but strangely fails on retrieving them (i.e. fails on
multifile fu/1 in the dbmanager module doesn’t work, because that module then doesn’t recognise
fu/1 as a valid predicate. Neither does it work to declare
fu/1 as a dynamic predicate in the dbmanager module. Neither does declaring
fu/1 as transparent.
In fact, the only way that I got something to work was by making
fu/1 publicly available in the
localdb module, and then importing it with
use_module(localdb,[fu/1]) in the
dbmanager module. But that is obviously not ideal, because then
dbmanager couldn’t be used as a common library in multiple different other modules.
I can also get something to work by explicitly passing the calling module name as a variable to
getfu, but it’s a bit of a hack (and strangely isn’t needed when asserting, i.e. not needed in
Lastly, things also work if the calling program is not a module at all, but a simple program and there is not
multifile declaration in the
So, my question: is it possible to somehow declare the dynamic predicate (i.e. as multifile) in the common management module, and have it answer queries based on the predicates in the calling module?
It turns out the solution is in something called
context_module/1, which enables you to check what the calling module (i.e. the context) is. If you modify the
dbmanager module as follows, it works:
:- module( dbmanager, [ addfu/1, getfu/1, delfu/1]). :- module_transparent addfu/1, getfu/1, delfu/1. addfu(B):- asserta(fu(B)). delfu(B):- context_module(M), retract(M:fu(B)). getfu(B):- context_module(M), M:fu(B).