Object Prolog:重写谓词和使用谓词之间的区别

Object Prolog:重写谓词和使用谓词之间的区别,object,module,prolog,Object,Module,Prolog,我觉得自己真的很蠢,觉得自己错过了什么 我基本上有两个文件: 通用逻辑规则的module.pl(意味着可重用) state.pl当前场景的一个 在模块文件(module.pl)中,我声明: inside(Food,Eater,T) :- isTime(T), injestEvent(InjEvent), justAfter(T,InjEvent), actorOfEvent(InjEvent, Eater), objectOfEvent(InjEven

我觉得自己真的很蠢,觉得自己错过了什么

我基本上有两个文件:

  • 通用逻辑规则的
    module.pl
    (意味着可重用)
  • state.pl
    当前场景的一个
在模块文件(
module.pl
)中,我声明:

inside(Food,Eater,T) :-
    isTime(T),
    injestEvent(InjEvent),
    justAfter(T,InjEvent),
    actorOfEvent(InjEvent, Eater),
    objectOfEvent(InjEvent, Food).
Q1)我不得不用单例变量声明所有其他谓词(在同一个文件中),只是为了停止
module.pl
抱怨它们不存在:

isTime(_T).
justAfter(_Time,_Event).

actorOfEvent(_Event, _ActorOfEvent).
objectOfEvent(_Event,_ActorOfEvent).
是这样吗

Q2)我不能使用像
justAfter/2
我的另一个文件这样的谓词,除非它说:

用户的本地定义:justAfter/2覆盖从模块的弱导入


如何使用从模块中导入的谓词,而不是重新定义它?

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).
---------------------
?- use_module(module).
其结果是:

?- [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.
您试图通过添加本地定义来解决此错误。但这只会导致你描述的第二个问题。当您执行以下操作时:

----- 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).
---------------------
?- use_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.
尽管这些是警告而不是错误,但调用
内部/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.
跟踪清楚地表明,在错误的上下文中调用了“state”谓词

一个干净的解决方案是使用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.
----------------------
然后将“状态”表示为:

快速测试(安装Logtalk后):

作为奖励,您可以根据需要定义任意多个“状态”对象。您还可以在
common
对象中对“state”谓词进行默认定义。当“state”对象不提供特定谓词的定义时,将继承并使用这些谓词。例如,让我们在
common
中添加以下子句:

objectOfEvent(injEvent, drink).
并从
状态
中删除(或注释掉)事件(injent,food)对象的子句。保存、重新加载并重试查询将为您提供:

?- {*}.   % 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的原因之一)。

添加“面向对象”的基本形式非常简单。 假设模块逻辑中有一个子句:

:- module(logic, [inside/4]).

% apply the rule to a specified module (expected to be a state object)
inside(M,Food,Eater,T) :-
    M:isTime(T),
    M:injestEvent(InjEvent),
    M:justAfter(T, InjEvent),
    M:actorOfEvent(InjEvent, Eater),
    M:objectOfEvent(InjEvent, Food).
我们有很多相关的状态对象:在state1.pl文件中

isTime(10).
injestEvent(eat).
justAfter(10, eat).
actorOfEvent(eat, mick).
objectOfEvent(eat, food).
在state2.pl文件中

isTime(20).
injestEvent(sleep).
justAfter(20, sleep).
actorOfEvent(sleep, everyone).
objectOfEvent(sleep, dream).
然后可能的会议:

?- [logic].
true.

?- s1:consult(state1).
true.

?- s2:consult(state2).
true.

?- inside(s1,Food,Eater,T).
Food = food,
Eater = mick,
T = 10.

?- inside(s2,What,Who,T).
What = dream,
Who = everyone,
T = 20.
一个值得尝试的小概括:

inside(M,Food,Eater,T) :-
    resolve(M),
    M:isTime(T),
    ...
resolve/1可能在哪里

resolve(M) :- var(M) -> current_module(M), catch(M:isTime(_),_,fail) ; true.
此技巧启用“浏览对象”:

?- inside(M,X,Y,Z).
M = s2,
X = dream,
Y = everyone,
Z = 20 ;
M = s1,
X = food,
Y = mick,
Z = 10 ;
false.

Capelical的另一种选择是使用。它们由SWI Prolog引入,自1.3.0版以来,它们也可在Jekejeke Prolog中使用。如果不需要接收者,可以简单地使用下划线

文件state1.pl:

:- module(state1, [isTime/2, injestEvent/2, justAfter/3, 
                   actorOfEvent/3, objectOfEvent/3]).
:- reexport(logic).
_.isTime() := 10.
_.injestEvent() := eat.
_.justAfter(10) := eat.
_.actorOfEvent(eat) := mick.
_.objectOfEvent(eat) := food.
:- module(state2, [isTime/2, injestEvent/2, justAfter/3, 
                   actorOfEvent/3, objectOfEvent/3]).
:- reexport(logic).
_.isTime() := 20.
_.injestEvent() := sleep.
_.justAfter(20) := sleep.
_.actorOfEvent(sleep) := everyone.
_.objectOfEvent(sleep) := dream.
:- module(logic, [inside/4]).
M.inside(Food,Eater) := T :-
    T = M.isTime(),
    InjEvent = M.injestEvent(),
    InjEvent = M.justAfter(T),
    Eater = M.actorOfEvent(InjEvent),
    Food = M.objectOfEvent(InjEvent).
文件state2.pl:

:- module(state1, [isTime/2, injestEvent/2, justAfter/3, 
                   actorOfEvent/3, objectOfEvent/3]).
:- reexport(logic).
_.isTime() := 10.
_.injestEvent() := eat.
_.justAfter(10) := eat.
_.actorOfEvent(eat) := mick.
_.objectOfEvent(eat) := food.
:- module(state2, [isTime/2, injestEvent/2, justAfter/3, 
                   actorOfEvent/3, objectOfEvent/3]).
:- reexport(logic).
_.isTime() := 20.
_.injestEvent() := sleep.
_.justAfter(20) := sleep.
_.actorOfEvent(sleep) := everyone.
_.objectOfEvent(sleep) := dream.
:- module(logic, [inside/4]).
M.inside(Food,Eater) := T :-
    T = M.isTime(),
    InjEvent = M.injestEvent(),
    InjEvent = M.justAfter(T),
    Eater = M.actorOfEvent(InjEvent),
    Food = M.objectOfEvent(InjEvent).
文件逻辑.pl:

:- module(state1, [isTime/2, injestEvent/2, justAfter/3, 
                   actorOfEvent/3, objectOfEvent/3]).
:- reexport(logic).
_.isTime() := 10.
_.injestEvent() := eat.
_.justAfter(10) := eat.
_.actorOfEvent(eat) := mick.
_.objectOfEvent(eat) := food.
:- module(state2, [isTime/2, injestEvent/2, justAfter/3, 
                   actorOfEvent/3, objectOfEvent/3]).
:- reexport(logic).
_.isTime() := 20.
_.injestEvent() := sleep.
_.justAfter(20) := sleep.
_.actorOfEvent(sleep) := everyone.
_.objectOfEvent(sleep) := dream.
:- module(logic, [inside/4]).
M.inside(Food,Eater) := T :-
    T = M.isTime(),
    InjEvent = M.injestEvent(),
    InjEvent = M.justAfter(T),
    Eater = M.actorOfEvent(InjEvent),
    Food = M.objectOfEvent(InjEvent).
要使逻辑在state1和state2中也可见,请使用reexport/1。这允许向state1或state2发送消息,但仍将处理来自逻辑的方法。下面是一个运行示例:

Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.19)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

?- T = state1{}.inside(Food,Eater).
T = 10,
Food = food,
Eater = mick.

?- T = state2{}.inside(Food,Eater).
T = 20,
Food = dream,
Eater = everyone.
isTime/2、INJESTENT/2等的出口。。将随着即将发布的Jekejeke Prolog 1.3.1版的发布而消失,因为我们已经实现了('.')/3呼叫站点感知。但Jekejeke Prolog的结果是相同的:

Jekejeke Prolog 3, Runtime Library 1.3.0
(c) 1985-2018, XLOG Technologies GmbH, Switzerland

?- T = state1{}.inside(Food,Eater).
T = 10,
Food = food,
Eater = mick

?- T = state2{}.inside(Food,Eater).
T = 20,
Food = dream,
Eater = everyone

Logtalk很棒——我是Prolog的初学者,希望保持简单,但这让事情进展顺利,似乎非常适合我的任务。感谢您的详细回复PauloAlso建议大家看看这个类似的问题:^^^语法是一个救命稻草!对于Prolog dicts上的函数,也演示了非确定性,请参见此处的示例: