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

rep*_*eat 5 module prolog meta-predicate

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

  1. 限定非终结a//1在模块dcgAux(发音: " 二SEE-吴 "):

    :- module(dcgAux,[a//1]).
    
    a(0)    --> [].
    a(s(N)) --> [a], a(N).
    
  2. 运行以下查询 - 使用phrase/2apply: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手册页import_module/2:

    所有普通模块仅从用户导入,从用户导入.

  • SWI library(apply)只是"继承" system,但不是user.

  • 如果我们将模块克隆applyapplY(并传播新的模块名称),我们会观察到:

    ?- use_module(applY).
    true.
    
    ?- phrase(applY:foldl(a,[s(0),s(s(0))]),[a,a,a]).  % was: ERROR
    true.                                              % now: OK!
    

请分享您对我如何/应该如何进行的想法!

(我还没有与其他Prolog处理器进行类似的实验.)

fal*_*lse 6

这是Quintus传统中基于谓词的模块系统的固有特征/错误.也就是说,这个模块系统最初是为Quintus Prolog开发的.它随后被SICStus采用(0.7 1之后),然后(或多或少)采用13211-2,然后采用YAP,并且(经过一些修改)由SWI采用.

这里的问题是一个明确的资格意味着什么.只要目标不是元谓词,事情就可以轻易解决:采用最内层资格的模块.但是,一旦有了元谓词,就需要将元参数告知该模块; 或不.如果通知了元参数,我们说冒号设置了调用上下文,如果没有,那么为此目的需要一些其他方法.

在Quintus传统中,元参数被考虑在内.结果你看到了.因此,您无法直接在同一模块中比较同一元谓词的两个实现.还有其他方法,尤其是IFECLiPSe,它们不会通过冒号改变调用上下文.这有利有弊.最好的是逐个比较它们.

这是最近的一个案例.将lambdas以及如何将它们放入SICStus,SWIECLiPSe中的模块中.

至于Quintus/SICStus/YAP/SWI模块系统,我宁愿以最保守的方式使用它.那是:

  • 没有明确的资格,认为中缀:是内部的东西

  • 干净,可检查的元声明 - 故意插入未定义的谓词,只是为了查看交叉引用是否能够检测到问题(在SWI中是check或者make).

  • 使用共同的子集,避免许多花里胡哨 - 有许多好的扩展...

  • 在行人方式做更多功能:通过添加适当的模块并添加虚拟定义来重新导出.同样,不是重命名,而是从接口模块导入内容.

  • 始终意识到模块系统本质上存在一些限制.无论你如何扭曲或扭转它.没有完全无缝的模块系统,因为模块的目的是分离代码和关注点.


1:确切地说,SICStus对Quintus模块的改编仅包括声明中的:模块敏感参数meta_predicate.0..9对于基于高阶编程非常重要的整数call/N仅在20年后的2011-03-08发布的4.2.0中引入 .