I am using XSB within a project that involves some data mining and probabilistic inductive logic programming, and I would like to provide some baselines. For this I would like to use Fabrizio Riguzzi's SWI-Prolog linear and logistic regression programs, which ultimately rely on his matrix library. Of course, I could use Janus or the C-interface to interface any other matrix library or spin my own C functions, but since I don't care about efficiency here I thought it might be easiest to simply port that library.
However, it is written in a very functional style, with clauses such as
matrix_div_scal(A,V,B):-
maplist(maplist(div(V)),A,B).
Even if I import the maplists from the swi compatibility library in the matrix module, I get an error that "no predicate usermod:maplist/3" exists.
Tracing reveals that the outer maplist is recognised correctly and only the inner maplist is considered unknown.
To me, this seems to contradict "All occurrences of T/N in M are in a file are normally associated
with the same module" from the Manual, but I think I am just fundamentally misunderstanding module inference.
Is there any good practice advice as to how to approach a port using a lot of such functional programming constructs?
I think I know what is going on. Note that the predicate/functor maplist appears both as maplist/3 as the outer call (as a predicate) and as maplist/1 (as the functor of the first argument to the outer call). Now the definition of maplist probably makes a call of the form call(P,X,Y). Now call/3 uses the module of the first argument to make the predicate symbol for the resulting call. So here the maplist/1 functor is not imported, so it is in usermod, and thuse the maplist/3 call is also to maplist in usermod.
One way to fix this is to import maplist/1 from (wherever). Then the call/3 will calll maplist/3 in the correct module. (Even though that module does not define maplist/1, you can import it. It's only a problem is you really call maplist/1, and in this case you won't, so all should be fine.)
I agree this is not optimal, but I know of no (reasonable) way to make call/3 know the right module to use for the call, in this case.
(It's possible that the maplist definition is using some other way to construct the maplist/3 term from the maplist/1 term to make the call, and if so, it might lose the module in some other way, and then this proposed way to fix your problem might not work...)
You were absolutely right! The "fake import" did fix the issue. What I have now done is just put explicit module qualifications on any predicate call within a maplist, and that also solved the problem.
Last edit: Felix Weitkämper 2023-12-14
Yes, explicit module modifiers override the module associated with the symbol (at least in all places we remembered to add the necessary code :-).