Why do unique module qualifiers match facts from other modules?

I’m investigating the curious behavior of module/2.

?- assertz(:- module(foo1, [f/1])).
true.

?- foo1:assertz(f(1)).
true.

?- foo1:f(1).
true.

?- foo2:f(1).
Correct to: "foo1:f(1)"? no
ERROR: Undefined procedure: foo2:f/1
ERROR: In:
ERROR:    [8] foo2:f(1)
ERROR:    [7] <user>

Makes sense to me. But then (from scratch)…

?- assertz(:- module(foo1, [f/1])).
true.

?- assertz(f(1)).
true.

?- foo1:f(1).
true.

?- foo2:f(1).
true.    % Wait, what? foo2 doesn't appear in my program. Should fail?

How does f get added to foo2 when I don’t mention foo2?

You don’t need assertz to demonstrate this. Here’s an example, which I’ve put in /tmp/m.pl:

:- module(foo1, [f/1]).
f(1).

Then:

?- use_module('/tmp/m.pl').
true.

?- f(Z).  % use_module brought f/1 into user "namespace"
Z = 1.

?- foo1:f(Z).
Z = 1.

?- listing(f).
foo1:f(1).

But this puzzles me:

?- foo2:f(Z).
Z = 1.

Anyway, for more sleuthing:

?- forall(predicate_property(f(_), P), format('~q~n', [P])).
interpreted
visible
static
imported_from(foo1)
file('/tmp/m.pl')
line_count(3)
number_of_clauses(1)
number_of_rules(0)
last_modified_generation(4591)
defined
size(240)

and I get exactly the same results with foo1:f(_), m:f(_), etc.

That query creates the module foo2. After, try:

?- current_module(foo2).
true.
1 Like

But why would this also put f/1’s definition into module foo2?

1 Like

It doesn’t (strictly speaking). Your initial use_module/1 goal makes f/1 available in user. As all modules inherit by default from user, the foo2:f(Z) goal succeeds by looking up f/1 in user.

3 Likes

Note that this doesn’t create a module foo1. In fact, it creates a predicate :-/1 with a single fact. It may comes as a surprise, but :-/1 is not a predicate, so you can define it. Just assert(foo1:f(1)) creates a module foo1 with a predicate f/1. Next you can use export/1 and import/1 to import and export stuff from your module (or simply directly call in there).

2 Likes

Right! I discovered that since I posted. It looked like way because I was replicating what I was trying via the foreign language interface – trying to issue a directive through the API’s query/assert calls. This got left in because I thought I’d succeed somehow (it succeeded, but as an assert not as a directive). Noob mistake.