Prolog:覆盖谓词与使用谓词之间的区别 [英] Prolog: Difference between overriding predicate and using it

查看:97
本文介绍了Prolog:覆盖谓词与使用谓词之间的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我真的很愚蠢,觉得我想念一些东西.

I feel really stupid, and feel like I'm missing something.

我基本上有两个文件:

  • module.pl用于通用逻辑规则(可以重用)
  • state.pl当前情况下的一个
  • module.pl for the universal logic rules (meant to be reusable)
  • state.pl one for the current scenario

在模块文件(module.pl)中,我声明:

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)我不得不用单例变量声明所有其他谓词(在同一文件中),只是为了阻止module.pl抱怨它们不存在:

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).

对吗?

Q2)我不能在其他文件中使用像justAfter/2这样的谓词,而不必说:

Q2) I can't use those predicates like justAfter/2 my other file without it saying:

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

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?

推荐答案

Prolog模块旨在隐藏辅助谓词.它们没有提供允许将谓词声明与谓词定义分开的接口的概念.这就是为什么如果您导出未定义的谓词,编译器会抱怨的原因.根据您的描述,我假设您尝试了类似的操作:

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:

----- 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.

您试图通过添加本地定义来解决此错误.但这只会导致您描述的第二个问题.当您执行以下操作时:

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:

?- use_module(module).

您导入由module导出的 all 谓词,包括要在state.pl中定义的谓词.因此,编译器在加载state.pl时警告您,该文件将覆盖那些谓词.例如.与:

You import all the predicates exported by module, including those that you want to define in state.pl. Therefore, the compiler warns you, when loading state.pl, that this file is overriding those predicates. E.g. with:

----- 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谓词不会不会给您您想要的东西:

Although these are warnings and not errors, calling the inside/3 predicate will not give you what you want:

?- inside(Food,Eater,T).
true.

绑定在哪里?!?让我们跟踪该调用以突出显示原因:

Where are the bindings?!? Let's trace the call to highlight the cause:

?- 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.

该跟踪清楚表明在错误上下文中正在调用状态"谓词.

The trace makes it clear that the "state" predicates are being called in the wrong context.

一个干净的解决方案是使用Logtalk对象而不是Prolog模块. Logtalk扩展了Prolog,并支持大多数系统,包括SWI-Prolog.它支持接口/协议作为一等实体(解决您提到的第一个问题),并在其使用上下文中支持继承和调用谓词(解决第二个问题).您可以使用例如

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.

----- 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.
----------------------

,然后将状态"表示为:

and then represent "state" as:

----- state.lgt -----
:- object(state, extends(common)).

isTime(1).
injestEvent(injEvent).
justAfter(1, injEvent).
actorOfEvent(injEvent, eater).
objectOfEvent(injEvent, food).

:- end_object.
---------------------

快速测试(安装Logtalk之后):

A quick test (after installing Logtalk):

$ swilgt
...
?- {common, state}.
...
true.

?- state::inside(Food,Eater,T).
Food = food,
Eater = eater,
T = 1.

作为奖励,您可以根据需要定义尽可能多的状态"对象.您还可以为common对象中的状态"谓词提供默认定义.当状态"对象未提供特定谓词的定义时,将继承并使用它们.例如,让我们在common子句中添加

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 to common the clause:

objectOfEvent(injEvent, drink).

并从state中删除(或注释掉)子句objectOfEvent(injEvent, food)..保存并重新加载并重试查询将为您提供:

and delete (or comment out) the clause objectOfEvent(injEvent, food). from state. Save and reload and retrying the query will give you:

?- {*}.   % abbreviation for Logtalk's make
% Redefining object common
...
% Redefining object state
...
true.

?- state::inside(Food,Eater,T).
Food = drink,
Eater = eater,
T = 1.

如果需要,您还可以动态创建新的状态对象,而不用在源文件中定义它们.例如:

If needed, you can also dynamically create new state objects instead of defining them in source files. For example:

?- create_object(s2, [extends(common)], [], [isTime(42), ...]).

可能不是您正在寻找的答案,但这也是最佳答案是为作业使用正确的工具^ H ^ H ^ H ^ H封装机制的情况.您的编程模式也是一种很常见的模式(这也是开发Logtalk的原因之一).

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).

这篇关于Prolog:覆盖谓词与使用谓词之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆