在SWI Prolog manual ,我发现了以下评论:
For example, assume an application that can reason about multiple worlds. It is attractive to store the data of a particular world in a module, so we extract information from a world simply by invoking goals in this world.
这实际上很好地描述了我要实现的目标。但是我遇到了一个问题。虽然我确实想为许多不同的世界建模,但我也想在所有这些世界中分享一些东西。所以我的想法是为每个世界中真实的事物创建一个 allworlds
模块,为每个我想要推理的世界创建一个模块,后者从前者导入。所以我会在 REPL 中做这样的事情:
allworlds:asserta(grandparent(X, Z) :- (parent(X, Y), parent(Y, Z))).
allworlds:dynamic(parent/2).
add_import_module(greece, allworlds, start).
greece:asserta(parent(kronos, zeus)).
greece:asserta(parent(zeus, ares)).
现在我想查询 greece:grandparent(kronos, X)
并得到 X = ares
,但我得到的只是 false
。当 allworlds:grandparent
调用 parent
时,它不会像我希望的那样调用 greece:parent
,而是 allworlds:parent
。我的研究似乎表明我需要使 grandparent
谓词模块透明。但是调用 allworlds:module_transparent(grandparent/2).
并没有解决这个问题,而且它也被弃用了。这就是我被困的地方。我怎样才能让这个工作?是meta_predicate/1
解决方案的一部分?不幸的是,我无法了解其文档。
最佳答案
Prolog 模块没有为“多世界”设计模式提供好的解决方案。值得注意的是,使谓词成为元谓词(或模块透明或多文件)将是一个有问题的 hack。但是这种模式对于 Logtalk 来说是微不足道的,它是一种扩展 Prolog 的语言,可以将大多数 Prolog 系统用作后端编译器。针对您的问题的最小(但不是唯一)解决方案是:
:- object(allworlds).
:- public(grandparent/2).
grandparent(X, Z) :-
::parent(X, Y),
::parent(Y, Z).
:- public(parent/2).
:- end_object.
:- object(greece,
extends(allworlds)).
parent(kronos, zeus).
parent(zeus, ares).
:- end_object.
在这里,当公共(public)谓词需要访问时,我们使用继承(各个世界继承公共(public)知识)和消息到 self(::/1
控制结构)特定于世界的谓词定义(self 是接收消息的对象/世界 - 在示例中为 grandparent/2
)。
假设代码保存在 worlds.lgt
文件中,并且您使用 SWI-Prolog 作为后端:
$ swilgt
...
?- {worlds}.
% [ /Users/pmoura/worlds.lgt loaded ]
% (0 warnings)
true.
?- greece::grandparent(kronos, X).
X = ares.
附言如果在 Windows 上运行,请在安装 Logtalk 后使用“开始”菜单中的“Logtalk - SWI-Prolog”快捷方式。
关于module - Prolog:调用谓词时考虑动态模块中的子句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67810114/