使用SWI-Prolog (多线程,64 位,版本 7.3.5), 我们一步步进行:
定义dcg模块
dcgAux
中的非终结符a//1
(发音:“di-SEE-goh”)::- module(dcgAux,[a//1]). a(0) --> []. a(s(N)) --> [a], a(N).
使用
phrase/2
运行以下查询和apply:foldl/4
:?- use_module([library(apply),dcgAux]). true. ?- phrase( foldl( a,[s(0),s(s(0))]),[a,a,a]). true. ?- phrase( foldl(dcgAux:a,[s(0),s(s(0))]),[a,a,a]). true. ?- phrase(apply:foldl(dcgAux:a,[s(0),s(s(0))]),[a,a,a]). true. ?- phrase(apply:foldl( a,[s(0),s(s(0))]),[a,a,a]). ERROR: apply:foldl_/4: Undefined procedure: apply:a/3
нет! 真是一个惊喜——而且不是一个好惊喜。我们是否遗漏了一些未知的未知因素?
要摆脱上述令人恼火的行为,我们必须首先找出导致它的原因:
?- import_module(apply,M), M=user. false. ?- phrase(apply:foldl(a,[s(0),s(s(0))]),[a,a,a]). ERROR: apply:foldl_/4: Undefined procedure: apply:a/3 ?- add_import_module(apply,user,end). true. ?- import_module(apply,M), M=user. % sic! M = user. % `?- import_module(apply,user).` fails! ?- phrase(apply:foldl(a,[s(0),s(s(0))]),[a,a,a]). true.
发生了什么事?我的看法是这样的:
- 传递给
foldl/4
的目标的模块扩展是有限的。 引自SWI-Prolog manual page on
import_module/2
:All normal modules only import from user, which imports from system.
SWI 的
library(apply)
仅“继承”于系统
,而不是用户
。如果我们将模块
apply
克隆到applY
(并传播新模块名称),我们会观察到:?- use_module(applY). true. ?- phrase(applY:foldl(a,[s(0),s(s(0))]),[a,a,a]). % was: ERROR true. % now: OK!
请分享您对我可以/应该如何进行的想法!
(我还没有使用其他 Prolog 处理器进行类似的实验。)
最佳答案
这是 Quintus 传统中基于谓词的模块系统的固有特征/错误。也就是说,这个模块系统首先是为Quintus Prolog开发的。它随后被 SICStus(0.71 之后)采用,然后(或多或少)被 13211-2 采用,然后被 YAP 和(经过一些修改)被 SWI 采用。
这里的问题是显式限定到底意味着什么。只要目标不是元谓词,事情就可以轻松解决:采用最内层限定的模块。然而,一旦有了元谓词,元参数就需要被告知该模块;或不。如果元参数被告知,我们就说冒号设置了调用上下文,如果没有,则需要一些其他方法来达到此目的。
在 Quintus 传统中,元参数被考虑在内。结果你看到了。因此,您无法直接比较同一模块中同一元谓词的两个实现。还有其他最值得注意的方法 IF和 ECLiPSe不会通过冒号更改调用上下文。这有优点也有缺点。最好是具体情况进行比较。
这是一个最近的案例。拿lambdas以及如何将它们放入模块中 在SICStus,in SWI ,和in ECLiPSe .
对于Quintus/SICStus/YAP/SWI模块系统,我宁愿以最保守的方式使用它。即:
没有明确的限定,将中缀
:
视为内部内容干净、可检查的元声明 - 故意插入未定义的谓词,只是为了查看交叉引用是否能够检测到问题(在 SWI 中是
check
或制作
)。使用公共(public)子集,避免许多花哨的东西 - 有许多善意的扩展...
以简单的方式做更多通用的事情:通过添加适当的模块重新导出并添加虚拟定义。同样,不要重命名,而是从接口(interface)模块导入内容。
始终意识到模块系统有固有一些限制。无论你如何扭转或转动它。不存在完全无缝的模块系统,因为模块的真正目的就是分离代码和关注点。
1:准确地说,SICStus 对 Quintus 模块的改编仅在 meta_predicate
声明中包含用于模块敏感参数的 :
。整数 0..9
对于基于 call/N
的高阶编程非常重要,直到大约 20 年后才被引入
4.2.0 released 2011-03-08 .
关于传递给库元谓词的目标的模块扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32141168/