传递给库元谓词的目标的模块扩展

标签 module prolog meta-predicate

使用SWI-Prolog (多线程,64 位,版本 7.3.5), 我们一步步进行:

  1. 定义模块 dcgAux 中的非终结符 a//1(发音:“di-SEE-goh”):

    :- module(dcgAux,[a//1]).
    
    a(0)    --> [].
    a(s(N)) --> [a], a(N).
    
  2. 使用 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
    

    нет! 真是一个惊喜——而且不是一个好惊喜。我们是否遗漏了一些未知的未知因素?

  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 传统中,元参数被考虑在内。结果你看到了。因此,您无法直接比较同一模块中同一元谓词的两个实现。还有其他最值得注意的方法 IFECLiPSe不会通过冒号更改调用上下文。这有优点也有缺点。最好是具体情况进行比较。

这是一个最近的案例。拿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/

相关文章:

module - 模块中的函数语法错误,OCaml

Prolog:单引号和双引号的不同行为

macros - 元谓词映射列表的测试目标扩展

将谓词应用于列表元素的 Prolog 映射过程

module - 在 SWI-Prolog 中,meta_predicate 的数字参数意味着什么?

import - DLL加载失败: Python modules accessible through Spyder but import fail in cmd

java - JBoss - 在运行时加载新模块

node.js - 带有 Passport 的 nodejs/hapi 应用程序中的模块化

Prolog:全局堆栈出错,对我来说看起来像是一级递归

list - 关于如何在序言中对列表中的元素求和的一些麻烦