Module 跨多个模块定义谓词的部分

Module 跨多个模块定义谓词的部分,module,prolog,swi-prolog,Module,Prolog,Swi Prolog,我试图编写一个谓词move/3,它处理几种术语,每种术语都在一个单独的文件中定义。我尝试使用模块来实现这一点,因为文件包含其他谓词,这些谓词应该适当地命名 因此,我创建了一个模块cat.prolog,内容如下: :- module(cat, [move/3]). :- multifile(move/3). move(cat(C), P, cat(C2)) :- ... 类似于dog.prolog 和main.prolog带有: :- use_module(['cat.prolog'],

我试图编写一个谓词
move/3
,它处理几种术语,每种术语都在一个单独的文件中定义。我尝试使用模块来实现这一点,因为文件包含其他谓词,这些谓词应该适当地命名

因此,我创建了一个模块
cat.prolog
,内容如下:

:- module(cat, [move/3]).
:- multifile(move/3).

move(cat(C), P, cat(C2)) :-
   ...
类似于
dog.prolog

main.prolog
带有:

:- use_module(['cat.prolog'], [move/3]).
:- use_module(['dog.prolog'], [move/3]).

(various predicates that use move/3 and expecting the clauses from all imported modules to be applicable.)
正在尝试在SWI Prolog中运行此操作:

?- ['main.prolog'].
%  cat.prolog compiled into cat 0.00 sec, 4,800 bytes
ERROR: Cannot import dog:move/3 into module user: already imported from cat
Warning: /home/edmund/main.prolog:2:
        Goal (directive) failed: user:use_module([dog.prolog],[move/3])
% main.prolog compiled 0.00 sec, 10,176 bytes
true.
此时,我可以使用
dog:move/3
cat:move/3
,但不能使用
move/3
。它适用于
cat
情况,但不适用于
dog
情况


我觉得有一个非常明显的方法可以做到这一点。我尝试过以多种方式组合模块、导入和多文件指令,但仍然没有找到…

多文件/1语法很简单,但缺少一个简单的示例

我创建了3个模块文件:
pets.pl
cat.pl
dog.pl

:- module(pets, [test/0, move/3]).
:- multifile move/3.
move(A,B,C) :- writeln(pets-move(A,B,C)).
test :- forall(move(A,B,C), writeln(move(A,B,C))).

:- module(cat, []).
:- use_module(pets).
pets:move(A,B,C) :- writeln(cat-move(A,B,C)).

:- module(dog, []).
:- use_module(pets).
pets:move(A,B,C) :- writeln(dog-move(A,B,C)).
注意“dependent”文件中的相关语法
Module:Pred:-…

?- [cat,dog].
%  pets compiled into pets 0.00 sec, 3 clauses
% cat compiled into cat 0.01 sec, 7 clauses
% dog compiled into dog 0.00 sec, 3 clauses
true.

?- test.
Correct to: "pets:test"? yes
pets-move(_G41,_G42,_G43)
move(_G41,_G42,_G43)
cat-move(_G41,_G42,_G43)
move(_G41,_G42,_G43)
dog-move(_G41,_G42,_G43)
move(_G41,_G42,_G43)
true.

?- 

另一种解决方案是定义一个Logtalk协议(即接口),用于声明谓词,如
move/3
,然后定义实现该协议的任意数量的对象。您可以使用大多数Prolog编译器(包括SWI Prolog)运行Logtalk。例如:

:- protocol(pets).

    :- public(move/3).
    ...

:- end_protocol.


:- object(cat, implements(pets)).

    move(A, B, C) :-
        ...

:- end_object.


:- object(dog, implements(pets)).

    move(A, B, C) :-
        ...

:- end_object.
假设上面的每个实体都在自己的文件中定义,例如
pets.lgt
cat.lgt
、和
dog.lgt
,那么您可以执行以下操作:

$ swilgt
...
?- {pets, cat, dog}.
...
? - cat::move(A, B, C).
...

Logtalk支持原型和类/实例,因此您可以定义适合您的应用程序的任何类型的层次结构/程序结构。与颠覆多文件谓词相比,为不同实体提供不同的谓词实现也可能是一个更干净的解决方案。

第二个可行的解决方案,这次不使用Prolog的Logtalk扩展,下面是我关于使用
include/1
指令的评论:

----- common.pl -----
:- export(move/1).
---------------------

----- cat.pl -----
:- module(cat, []).
:- include(common).

move(cat).
---------------------

----- dog.pl -----
:- module(dog, []).
:- include(common).

move(dog).
---------------------

$ swipl
...
?- use_module(cat, []), use_module(dog, []).
% cat compiled into cat 0.00 sec, 4 clauses
% dog compiled into dog 0.00 sec, 4 clauses
true.

?- cat:move(X).
X = cat.

?- dog:move(X).
X = dog.

?- module_property(cat, exports(Exports)).
Exports = [move/1].

?- module_property(dog, exports(Exports)).
Exports = [move/1].
与Logtalk解决方案一样,多文件谓词不是答案

应该注意的是,在大多数Prolog模块系统中,包括SWI-Prolog,任何模块谓词都可以像上面的查询那样使用显式限定来调用。但是使用一个文件来保存公共位仍然有两个优点:(1)它使公共位在单个位置显式显示,并避免源代码重复;(2) 行为良好的应用程序应该只调用导出的谓词,并且有一些工具可以检测违反此原则的情况。在下边,包含的文件只是一个第一类实体,您考虑文件本身就是这样的。加载包含公共bits文件的模块时也必须小心,因为使用例如
consult/1
use\u module/1
会导致冲突:

?- [cat, dog].
% cat compiled into cat 0.00 sec, 4 clauses
ERROR: import/1: No permission to import dog:move/1 into user (already imported from cat)
% dog compiled into dog 0.00 sec, 4 clauses
true.

实际上,此解决方案可能会导致使用显式限定调用大多数或所有模块谓词。

您是否也尝试过在
main
模块中将move/3声明为多文件?我尝试过,但没有任何区别,仍然是关于它已导入的错误。谢谢,这看起来很有希望。有趣的是,猫和狗模块包含pets模块,而不是像我一样包含pets模块。这个解决方案是使用多文件谓词的一个很好的例子,但并没有给你一个简单的解决方案,例如,当谓词的所有子句都在pets命名空间中时,让猫移动。@PauloMoura:你的注释击中了问题的核心。我缺少一个明显的解决方案?我确实发布了一个有效的解决方案。到目前为止,他被否决了。但回到多文件谓词。我认为没有任何简单而明显的解决办法。多文件谓词始终属于单个命名空间(可能是伪模块用户)。因此,它的子句当然可以分散,但访问总是通过相同的模块前缀(即使是隐式的)。。。在使用include/1指令的cat和fog文件中包含的pets文件中使用export/1指令如何?这很可能是您可以分享可以解释为谓词声明的内容的最接近点。回答不错(+1),export/1、include/1之间的关系非常难以捉摸。但我不确定这个解决方案是否符合OP的问题。我对OP问题的解释是,他希望有一个通用的接口和该接口的不同实现(但这将有助于他提供更多的输入)。因此,最干净的解决方案是Logtalk one,它目前的票数为零,甚至早些时候还投了反对票。但向下的选民迄今为止提供了零工作解决方案。Logtalk的设计就是为了解决这类问题。Prolog模块是为零开销而设计的,而不是为了优雅地解决此类问题。所以,一个难以捉摸的模块解决方案是你能做的最好的。谢谢你的回答。这不是我想要的,但Logtalk听起来很有趣,所以我会仔细阅读。