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

时间:2015-08-21 13:10:15

标签: module prolog meta-predicate

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

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

    :- 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.
    
  4. 发生了什么事?我看到它的方式是:

    • 传递给foldl/4的目标的模块扩展是有限的。
    • 引自SWI-Prolog manual page on import_module/2

        

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

    • SWI的library(apply)仅“{继承”来自system,而不是user

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

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

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

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

1 个答案:

答案 0 :(得分:6)

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

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

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

这是最近的案例。取lambdas以及如何将它们放入模块中 在SICStus中,in SWIin ECLiPSe

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

  • 没有明确的资格,将中缀:视为内部内容

  • 干净,可检查的元声明 - 故意插入未定义的谓词,以查看交叉引用是否能够检测到问题(在SWI中check或{{ 1}})。

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

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

  • 始终注意模块系统固有某些限制。无论你如何扭曲或扭转它。没有完全无缝的模块系统,因为模块的目的是分离代码和关注点。

1:确切地说,SICStus'对于make声明中的模块敏感参数,Quintus模块的调整仅包含:。对基于meta_predicate的高阶编程非常重要的整数0..9仅在大约20年后才被引入 4.2.0 released 2011-03-08