Модули Prolog были разработаны для сокрытия вспомогательных предикатов.Они не предоставляют концепцию интерфейса, которая позволяет отделить объявления предикатов от определений предикатов.Вот почему компилятор жалуется, если вы экспортируете предикаты, которые не определены.Из вашего описания я предполагаю, что вы пробовали что-то вроде:
----- module.pl -----
:- module(module, [
inside/3, isTime/1, injestEvent/1, justAfter/2, actorOfEvent/2, objectOfEvent/2
]).
inside(Food,Eater,T) :-
isTime(T),
injestEvent(InjEvent),
justAfter(T,InjEvent),
actorOfEvent(InjEvent, Eater),
objectOfEvent(InjEvent, Food).
---------------------
, что приводит к:
?- [module].
ERROR: Exported procedure module:justAfter/2 is not defined
ERROR: Exported procedure module:isTime/1 is not defined
ERROR: Exported procedure module:injestEvent/1 is not defined
ERROR: Exported procedure module:objectOfEvent/2 is not defined
ERROR: Exported procedure module:actorOfEvent/2 is not defined
true.
Вы попытались обойти эту ошибку, добавив локальные определения.Но это просто приводит ко второй проблеме, которую вы описываете.Когда вы делаете что-то вроде:
?- use_module(module).
Вы импортируете все предикаты, экспортированные на module
, включая те, которые вы хотите определить в state.pl
.Поэтому при загрузке state.pl
компилятор предупреждает, что этот файл переопределяет эти предикаты.Например:
----- state.pl -----
isTime(1).
injestEvent(injEvent).
justAfter(1, injEvent).
actorOfEvent(injEvent, eater).
objectOfEvent(injEvent, food).
--------------------
мы получаем:
?- [state].
Warning: /Users/pmoura/Desktop/state.pl:1:
Local definition of user:isTime/1 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:2:
Local definition of user:injestEvent/1 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:3:
Local definition of user:justAfter/2 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:4:
Local definition of user:actorOfEvent/2 overrides weak import from module
Warning: /Users/pmoura/Desktop/state.pl:5:
Local definition of user:objectOfEvent/2 overrides weak import from module
true.
Хотя это предупреждения , а не ошибки, вызов предиката inside/3
будет не дать вам то, что вы хотите:
?- inside(Food,Eater,T).
true.
Где привязки?!?Давайте проследим вызов, чтобы выделить причину:
?- trace.
true.
[trace] ?- inside(Food,Eater,T).
Call: (8) module:inside(_2508, _2510, _2512) ? creep
Call: (9) module:isTime(_2512) ? creep
Exit: (9) module:isTime(_2512) ? creep
Call: (9) module:injestEvent(_2804) ? creep
Exit: (9) module:injestEvent(_2804) ? creep
Call: (9) module:justAfter(_2512, _2806) ? creep
Exit: (9) module:justAfter(_2512, _2806) ? creep
Call: (9) module:actorOfEvent(_2804, _2510) ? creep
Exit: (9) module:actorOfEvent(_2804, _2510) ? creep
Call: (9) module:objectOfEvent(_2804, _2508) ? creep
Exit: (9) module:objectOfEvent(_2804, _2508) ? creep
Exit: (8) module:inside(_2508, _2510, _2512) ? creep
true.
Трассировка проясняет, что предикаты «состояния» вызываются в неверном контексте.
AЧистое решение - использовать объекты Logtalk вместо модулей Prolog.Logtalk расширяет Prolog и поддерживает большинство систем, включая SWI-Prolog.Он поддерживает интерфейсы / протоколы как первоклассные объекты (которые решают первую упомянутую вами проблему) и поддерживает наследование и вызов предикатов в их контексте использования (который решает вторую проблему).Вы можете использовать, например,
----- common.lgt -----
:- object(common).
:- public([
inside/3, isTime/1, injestEvent/1, justAfter/2, actorOfEvent/2, objectOfEvent/2
]).
inside(Food,Eater,T) :-
% call the next predicates in "self", i.e. in the
% object that received the inside/3 message
::isTime(T),
::injestEvent(InjEvent),
::justAfter(T,InjEvent),
::actorOfEvent(InjEvent, Eater),
::objectOfEvent(InjEvent, Food).
:- end_object.
----------------------
и затем представлять «состояние» как:
----- state.lgt -----
:- object(state, extends(common)).
isTime(1).
injestEvent(injEvent).
justAfter(1, injEvent).
actorOfEvent(injEvent, eater).
objectOfEvent(injEvent, food).
:- end_object.
---------------------
Быстрый тест (после установки Logtalk):
$ swilgt
...
?- {common, state}.
...
true.
?- state::inside(Food,Eater,T).
Food = food,
Eater = eater,
T = 1.
КакБонус, вы можете определить столько «государственных» объектов, сколько вам нужно.Вы также можете иметь определения по умолчанию для предикатов "state" в объекте common
.Они будут наследоваться и использоваться, когда объекты «состояния» не предоставляют определения для конкретного предиката.Например, давайте добавим к common
предложение:
objectOfEvent(injEvent, drink).
и удалим (или закомментируем) предложение objectOfEvent(injEvent, food).
из state
.Сохраните, перезагрузите и повторите запрос:
?- {*}. % abbreviation for Logtalk's make
% Redefining object common
...
% Redefining object state
...
true.
?- state::inside(Food,Eater,T).
Food = drink,
Eater = eater,
T = 1.
При необходимости вы также можете динамически создавать новые объекты состояния вместо определения их в исходных файлах.Например:
?- create_object(s2, [extends(common)], [], [isTime(42), ...]).
Этот может не быть ответом, который вы искали, но это также тот случай, когда лучший ответ - использовать правильный инструмент ^ H ^ H ^ H^ H механизм инкапсуляции для работы.Ваш шаблон программирования также является довольно распространенным (и одна из причин, по которой был разработан Logtalk).