This may be specific to the SWI Prolog module system.
Suppose we have three Prolog modules (in the SWI-Prolog module system):
robin
(in filerobin.pl
)arthur
(in filearthur.pl
)helper
(in filehelper.pl
).
Predicates robin:robin/0
(i.e. predicate robin_hood/0
in module robin
) and predicate arthur:arthur/0
call predicate helper:helper/2
(which is exported by module helper
).
Predicate helper:helper/2
then should call a predicate toolshed/1
, which is different depending on the caller modules. I would like helper/2
to call the toolshed/1
predicate associated with the predicate that calls helper/2
.
In Java, one would pass an interface with a toolshed()
method to helper()
, so that helper()
can call the interface and end up at the correct implementation.
How do I do it in Prolog?
Example code:
robin.pl
:- module(robin,
[
robin/0
,toolshed/1
]).
:- use_module(library('helper.pl')).
robin :- helper(friar_tuck,help).
toolshed('a katana made by mastersmith Masamune').
toolshed('an ancient shovel with a sharpened blade').
toolshed('an Uzi 9mm with Norinco markings').
arthur.pl
:- module(arthur,
[
arthur/0
,toolshed/1
]).
:- use_module(library('helper.pl')).
arthur :- helper(merlin,help).
toolshed('a slightly musty grimoire').
toolshed('a jar of mandragore').
toolshed('a fresh toadstool').
helper.pl
:- module(helper,
[
helper/2
]).
helper(friar_tuck,help) :-
format("I will help you rout the Sheriff of Nottingham's men!~n"),
setof(X,toolshed(X),Tools),
format("I found these tools: ~q~n",[Tools]),
format("Have at them!~n").
helper(merlin,help) :-
format("I will help you rout Mordred's army!~n"),
setof(X,toolshed(X),Tools),
format("I found these tools: ~q~n",[Tools]),
format("Have at them!~n").
Put them into a director testing
:
testing
├── arthur.pl
├── helper.pl
└── robin.pl
Launch swipl
, set the library search path and load arthur.pl
:
?- assertz(file_search_path(library,'/home/me/testing')).
true.
?- use_module(library('arthur.pl')).
true.
?- arthur.
I will help you rout Mordred's army!
I found these tools: ['a fresh toadstool','a jar of mandragore','a slightly musty grimoire']
Have at them!
true.
So this works. toolshed/1
is exported by module arthur
and visible (and callable unqalified) by module helper
even though helper
does not import arthur.pl
(not quite sure how that works, mabye the exported predicates of all modules belonging to predicates currently on the stack are visible and accessible unqalified?).
But I can't load robin.pl
too:
?- use_module(library('robin.pl')).
ERROR: import/1: No permission to import robin:toolshed/1 into user (already imported from arthur)
true.
Ok, this is not surprising. But how do I get the result I want? I want to see this:
?- use_module(library('robin.pl')).
true.
?- robin.
I will help you rout the Sheriff of Nottingham's men!
I found these tools: ['a katana made by mastersmith Masamune','an Uzi 9mm with Norinco markings','an ancient shovel with a sharpened blade']
Have at them!
true.
multifile/1
directives fortoolshed/1
in botharthur.pl
androbin.pl
but that yields the same problem. – David Tonhoferhelper/2
intohelper/3
and pass it the list of tools found in the localtoolshed/1
? – Paul Brown