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).
你导入all导出的谓词module
,包括您想要定义的那些state.pl
。因此,编译器在加载时会警告您state.pl
,该文件正在覆盖这些谓词。例如。和:
----- state.pl -----
isTime(1).
injestEvent(injEvent).
justAfter(1, injEvent).
actorOfEvent(injEvent, eater).
objectOfEvent(injEvent, food).
--------------------
we get:
?- [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.
虽然这些是warnings而不是错误,调用inside/3
谓词will没有给你你想要的:
?- 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.
跟踪清楚地表明“状态”谓词正在被调用wrong语境。
一个干净的解决方案是使用 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.
作为奖励,您可以根据需要定义任意数量的“状态”对象。您还可以拥有默认定义对于“状态”谓词common
目的。当“状态”对象不提供特定谓词的定义时,这些将被继承和使用。例如,让我们添加到common
该条款:
objectOfEvent(injEvent, drink).
并删除(或注释掉)该条款objectOfEvent(injEvent, food).
from 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), ...]).
This 未必您正在寻找的答案,但这也是最好的答案是使用正确的工具^H^H^H^H 封装机制来完成工作的情况。您的编程模式也是一种非常常见的模式(也是开发 Logtalk 的原因之一)。