Having trouble using multifile/1 for multi-file predicates

I’m using: SWI-Prolog version: (threaded, 64 bits, version 8.2.4)

I want the code to: Enable multi-file declaration of predicates by use of multifile/1.

But what I’m getting is:

?- Warning: /home/.../prolog/minimal.pl:5:
Warning:    Local definition of minimal:bar/1 overrides weak import from foo
true.

whenever I try load the files as described below.

My code looks like this:

This is my MWE:

In file foo.pl:

:- module(foo, [bar/1]).

:- multifile bar/1.

In file minimal.pl:

:- module(minimal, []).

:- use_module(foo).

:- multifile bar/1.
bar(1).
bar(2).

I’ve tried this with and without declaring multifile/1 for bar in minimal.pl. I get the same result either way.

Am I missing something? Is it a bug? Any tips most appreciated!

This will just show a working example instead of showing you your mistakes. This is minimal enough that if you change just about anything related to the multifile predicates it will break so you can learn from it.

File: foo_1.pl

:- module(foo_1,[]).

:- multifile my_module:bar/1.

my_module:bar(Value) :-
    Value = "Hello from foo_1.".

File: foo_2.pl

:- module(foo_2,[]).

:- multifile my_module:bar/1.

my_module:bar(Value) :-
    Value = "Hello from foo_2.".

File: examples.pl

:- module(examples,
    [
        example/1
    ]).

:- use_module(foo_1).
:- use_module(foo_2).

:- multifile my_module:bar/1.

example(1) :-
    findall(Value,my_module:bar(Value),Values),
    format('Values: ~w~n',[Values]).

Example usage.

Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.28-20)
...

?- working_directory(_,'C:/Users/Groot').
true.

?- [examples].
true.

?- example(1).
Values: [Hello from foo_1.,Hello from foo_2.]
true.


If you have any questions just ask. :slightly_smiling_face:

1 Like

Thanks! So, iiuc, we need to prefix the any predicate declared as multifile/1 with the module it gets asserted into?

Am I alone in thinking that this is not even hinted at in the slightest from the documentation on multifile/1 :slight_smile: ?

I don’t believe so but as I can never remember exactly which module they will default to, IIRC it can vary, so I just make up a module name and use it and then don’t have to spend time using predicate_property/2 and such to figure out which modules they landed.


No. I think for many of us understanding the SWI-Prolog documentation is an acquired skill. The one thing that helped me and still helps me a lot in learning how the predicates work is to seek working examples of them. The best place to see correct usage of them is in the actual SWI-Prolog source code on GitHub. As a matter of fact, I tend to do searches of the code so often that I have a session of NotePad++ open for searching the Prolog and C code. The search in NotePad++ is so much better than using the GitHub search.

image

HTH

I don’t know how many people actually read the intro to the SWI-Prolog docs but it notes

This document is a reference manual . That means that it documents the system, but it does not explain the basics of the Prolog language and it leaves many details of the syntax, semantics and built-in primitives undefined where SWI-Prolog follows the standards. This manual is intended for people that are familiar with Prolog.

You have to love it. :grinning:


EDIT

Forgot to note that the directory I use with NotePad++ for searching includes several of the repositories from the SWI-Prolog GitHub account. This way more can esaily be added, including packs and newer versions can easily be updated.

C:\Users\Groot\Documents\GitHub\SWI-Prolog>dir /b
packages-chr-master
packages-http-master
packages-pldoc-master
packages-RDF-master
packages-semweb-master
packages-sgml-master
packages-xpce-master
plweb-blog-master
plweb-examples-master
plweb-master
plweb-www-master
swipl-devel-master
swipl-server-js-client-master
swish-master
1 Like

Thanks for much for the pointers, @EricGT!

Just for sake have giving a clear and unambiguous example of how to fix my code, to help future seekers, this how to change the code to correctly define multifile predicates (in the way I’d wanted):

In foo.pl:

:- module(foo, [bar/1]).

:- multifile bar/1.

And in minimal.pl:

:- module(minimal, []).

:- use_module(foo).

foo:bar(1).
foo:bar(2).

So, the fix is just noting that when we add a new clause for the predicate declared as multifile/1, we need to prefix it with the module into which the clauses are added.

Now that I think of it, this is consistent with use of other multifile predicates from the standard library, like term_expansion/2 or has_type/2.

I added a note to the reference: (multifile)/1

Predicates loaded from source end up in the module in which they appear. It is possible to qualify the head of a clause, which causes the clause to be added to a predicate inside the specified module. The body is executed in the current source module. It is is also possible to qualify the whole clause, though there are few good reasons to do so. If you do, the clause acts as if appearing in the specified module. Thus, given m1 we have

  • p(a) ends up in m1
  • m2:p(a) ends up in m2
  • m2:p(a) :- q. ends up in m2, but calls m1:q
  • m2:(p(a) :- q). ends up in m2 and calls m2:q

Typically a multifile predicate belongs to a specific module. This is the module that calls the multifile predicate to achieve something. It declares it as e.g. (assuming we work in m1):

:- multifile p/1.

Often it does not provide clauses to it. It may though and if it does it does not need to qualify these clauses.

Other module files add to m1:p/1 using

:- multifile m1:p/1.

Next it adds clauses using

m1:p(a).
m1:p(X) :- q(X).

q(X) :- ...

Roughly there are two use cases for multifile predicates. First of all for pure (often data) predicates and second for hooks. Hooks are typically semidet and called by the “owning” module as

:- multifile x_hook/1.

x(X) :-
    x_hook(X),
    !.
x(X) :-
    <do default things>

Note that the clauses of multifile predicates appear in the order they appear in each file. From different files, the order is defined by the order of loading. As this is not well defined one should try to avoid relying on the ordering.

3 Likes