I feel really stupid, and feel like I'm missing something.
I've basically got two files:
module.pl
for the universal logic rules (meant to be reusable)state.pl
one for the current scenario
In the module file (module.pl
) I've declared:
inside(Food,Eater,T) :-
isTime(T),
injestEvent(InjEvent),
justAfter(T,InjEvent),
actorOfEvent(InjEvent, Eater),
objectOfEvent(InjEvent, Food).
Q1) I've had to declare all those other predicates with singleton variables (in the same file), just to stop module.pl
complaining they don't exist:
isTime(_T).
justAfter(_Time,_Event).
actorOfEvent(_Event, _ActorOfEvent).
objectOfEvent(_Event,_ActorOfEvent).
Is that right?
Q2) I can't use those predicates like justAfter/2
my other file without it saying:
Local definition of user:justAfter/2 overrides weak import from module
How can I use the predicates I've imported from my module, rather redefining it?
It's very simple to add a basic form of 'object orientation'. Let's say we have a clause in a module logic:
and we have a lot of state objects pertinent: in a file state1.pl
and in a file state2.pl
then a possible session:
A small generalization, worth to try:
where resolve/1 could be
this trick enable 'browsing the objects':
An alternative to CapelliC is the use of Prolog dicts. They have been introduced by SWI-Prolog and since release 1.3.0 they are also available in Jekejeke Prolog. If the receiver is not needed, one can simply use an underscore.
File state1.pl:
File state2.pl:
File logic.pl:
To make the logic also visible in state1 and state2 use reexport/1. This allows sending a message to state1 or state2, but nevertheless a method from logic will be processed. Here is an example run:
The exports of isTime/2, injestEvent/2, etc.. will go away with the upcoming release 1.3.1 of Jekejeke Prolog when we have made ('.')/3 call-site aware. But the result for Jekejeke Prolog is the same:
Prolog modules were designed to hide auxiliary predicates. They don't provide a concept of interface that allows separating predicate declarations from predicate definitions. That's why the compiler complains if you export predicates that are not defined. From your description, I assume you tried something like:
which results in:
You attempted to workaround this error by adding local definitions. But this just result in the second problem you describe. When you do something like:
You import all the predicates exported by
module
, including those that you want to define instate.pl
. Therefore, the compiler warns you, when loadingstate.pl
, that this file is overriding those predicates. E.g. with:we get:
Although these are warnings and not errors, calling the
inside/3
predicate will not give you what you want:Where are the bindings?!? Let's trace the call to highlight the cause:
The trace makes it clear that the "state" predicates are being called in the wrong context.
A clean solution is to use Logtalk objects instead of Prolog modules. Logtalk extends Prolog and supports most systems, including SWI-Prolog. It supports interfaces/protocols as first-class entities (which solve the first problem you mention) and supports inheritance and calling predicates in their usage context (which solves the second problem). You could use e.g.
and then represent "state" as:
A quick test (after installing Logtalk):
As a bonus, you can define as many "state" objects as you need. You can also have default definitions for the "state" predicates in the
common
object. These will be inherited and used when the "state" objects don't provide a definition for a particular predicate. For example, let's add tocommon
the clause:and delete (or comment out) the clause
objectOfEvent(injEvent, food).
fromstate
. Save and reload and retrying the query will give you:If needed, you can also dynamically create new state objects instead of defining them in source files. For example:
This may not be the answer you were looking for but this is also the case where the best answer is to use the right tool^H^H^H^H encapsulation mechanism for the job. Your programming pattern is also a quite common one (and one of the reasons Logtalk was developed).