【问题标题】:What kind of meta argument is the first argument of predicate_property/2?predicate_property/2 的第一个参数是什么元参数?
【发布时间】:2014-06-25 14:48:58
【问题描述】:

换句话说,应该是0 还是: 还是别的什么? Prolog 系统 SICStus、YAP 和 SWI 都将其表示为 :。这合适吗?不应该是0,意思是call/1可以调用的术语吗?

检查您的系统类型:

| ?- predicate_property(predicate_property(_,_),P).
P = (meta_predicate predicate_property(:,?)) ? ;
P = built_in ? ;
P = jitted ? ;
no

我应该补充一点,元参数——至少在这里使用的形式——不能保证我们期望从纯关系中得到相同的代数属性:

?- S=user:false, predicate_property(S,built_in).
S = user:false.

?- predicate_property(S,built_in), S=user:false.
false.

这是来自 ISO/IEC 13211-2 的相关部分:

7.2.2 predicate_property/2

7.2.2.1 说明

predicate_property(Prototype, Property) 在模块M
调用上下文中为真,前提是该过程 与
参数 Prototype 关联具有谓词属性 Property.

...

7.2.2.2 模板和模式

predicate_property(+prototype, ?predicate_property)

7.2.2.3 错误

a) Prototype 是一个变量
instantiation_error

...

c) Prototype 既不是变量也不是可调用项
type_error(callable, Prototype).

...

7.2.2.4 示例

Goals attempted in the context of the module
bar.

predicate_property(q(X), exported).
    succeeds, X is not instantiated.

...

【问题讨论】:

    标签: module prolog iso-prolog meta-predicate


    【解决方案1】:

    这是一个有趣的问题。首先我认为有两个 各种predicate_property/2 谓词。第一种 接受一个可调用的,旨在与 例如香草解释器和内置插件,如 write/1nl/0等,即:

    solve((A,B)) :- !, solve(A), solve(B).
    solve(A) :- predicate_property(A, built_in), !, A.
    solve(A) :- clause(A,B), solve(B).
    

    对于第一种,我猜是 0 元参数说明符 可以正常工作。第二种predicate_property/2 谓词与谓词指示符一起使用。可调用 和谓词指示符都是已经定义的概念 在 ISO 核心标准中。

    谓词指示符的形式为 F/N,其中 F 是一个原子 N是整数。事情变得有点复杂 如果模块存在,尤其是因为操作员 (:)/2 与 (/)/2 的优先级。如果谓词属性有效 使用谓词指示符,我们仍然可以编写 vanilla 口译员:

    solve((A,B)) :- !, solve(A), solve(B).
    solve(A) :- functor(A,F,N), predicate_property(F/N, built_in), !, A.
    solve(A) :- clause(A,B), solve(B).
    

    这里我们松开了一个可能的元参数的连接 0,例如solve/1,具有谓词属性。因为 functor/3 通常没有元谓词声明。还 通过functor/3传输模块信息到 predicate_property/2 是不可能的,因为 functor/3 与 模块,它通常没有可以处理的实现 包含模块限定的参数。

    现在有两个问题:
    1)我们可以给谓词打字和/或我们应该给谓词打字吗 比如functor/3
    2)我们可以扩展functor/3以便它可以传送模块吗 资格。

    以下是我的想法:
    1) 需要更精细的类型系统。一个会 允许重载具有多种类型的谓词。为了 例如functor/3 可以有两种类型:

      :- meta_predicate functor(?,?,?).
      :- meta_predicate functor(0,?,?).
    

    重载多种类型的真正威力只有 在 (=)/2 等谓词中大放异彩。在这里我们会有:

      :- meta_predicate =(?,?).
      :- meta_predicate =(0,0).
    

    因此允许更多类型推断,如果一侧 (=)/2 是我们可以推断出对方的目标 也是一个目标。

    但事情没那么简单,它可能会让 感觉还有一种类型转换或其他形式 限制过载的机制。什么东西 仅引入元谓词并未涵盖 指示。这将需要内部进一步的构造 条款和目标。

    学习形式 lambda Prolog 或一些依赖类型 系统,可能是有利的。例如 (=)/2 可以 被视为由类型 A 参数化,即:

     :- meta_predicate =(A,A).
    

    2) 对于 Jekejeke Prolog,我提供了一个替代方案 functor/3 实现。谓词是sys_modfunc_site/2。 它像functor/3 一样双向工作,但返回 并接受谓词指示符作为一个整体。 以下是一些示例运行:

     ?- sys_modfunc_site(a:b(x,y), X).
     X = a:b/2
     ?- sys_modfunc_site(X, a:b/2).
     X = a:b(_A,_B)
    

    谓词的结果可以称为泛化 谓词指标。这是 SWI-Prolog 已经理解的 例如在listing/1。所以它可以有相同的元参数 规范为listing/1。这是当前的:在 SWI-Prolog 中。 所以我们会,随后predicate_property/2 会 取 : 在它的第一个参数中:

     :- meta_predicate sys_modfunc_site(?,?).
     :- meta_predicate sys_modfunc_site(0,:).
    

    原版解释器,也可以处理模块,然后 内容如下。不幸的是,需要进一步的谓词, sys_indicator_colon/2,压缩一个合格的谓词 指示符变成一个普通的谓词指示符,因为我们的 predicate_property/2 不理解广义谓词 出于效率原因的指标:

    solve((A,B)) :- !, solve(A), solve(B).
    solve(A) :- 
          sys_modfunc_site(A,I), 
          sys_indicator_colon(J,I), 
          predicate_property(J, built_in), !, A.
    solve(A) :- clause(A,B), solve(B).
    

    上面实现了冒号 (:)/2 的局部语义, 与结肠的相当深远的语义相比 (:)/2 如 ISO 模块标准中所述。远方 达到语义在所有文字上赋予模块名称 的一个查询。本地语义只需要一个合格的 文字,只是将模块名称应用于该文字。

    Jekejeke 只实现局部语义 规定呼叫站点不改变。所以在引擎盖下 sys_modfunc_site/2sys_indicator_colon/2 也必须 转移呼叫站点,以便predicate_property/2 使 不合格谓词的正确决定,即解决 通过尊重导入等来命名谓词。

    最后一点结语:
    Jekejeke Prolog 的调用点传输是一个纯运行时 东西,并且不需要一些编译时操作,尤其是 在编译时没有特别添加模块限定符。因此 保留了某些代数性质。例如假设 我们有以下子句:

     ?- [user].
     foo:bar.
     ^D
    

    那么下面的事情就可以正常工作了,因为不仅sys_modfunc_site/2 是双向的,也是sys_indicator_colon/2:

      ?- S = foo:bar/0, sys_indicator_colon(R,S), predicate_property(R,static).
      S = foo:bar/0,
      R = 'foo%bar'/0
      ?- predicate_property(R,static), sys_indicator_colon(R,S), S = foo:bar/0.
      R = 'foo%bar'/0,
      S = foo:bar/0
    

    当然predicate_property/2 可以使用不同的输入和 输出模式。但我猜 SWI-Prolog 现象首先有一个 裸骨变量以当前模块为前缀的问题。和 由于false 不在user 中,而是在system 中,所以它不会显示false。 在输出模式下,它不会显示分辨率相等的谓词。 在 SWI-Prolog 中查看:

     ?- predicate_property(X, built_in), write(X), nl, fail; true.
     portray(_G2778)
     ignore(_G2778)
     ...
     ?- predicate_property(user:X, built_in), write(X), nl, fail; true.
     prolog_load_file(_G71,_G72)
     portray(_G71)
     ...
     ?- predicate_property(system:X, built_in), write(X), nl, fail; true.
     ...
     false
     ...
    

    但即使 SWI-Prolog predicate_property/2 谓词 允许条形骨骼变量,即输出目标,我们会看到更少 远距离语义中的交换性比局部语义中的交换性 语义。在意义深远的语义M:G 意味着解释G 在模块M 内部,即尊重模块M 的导入, 这可能会相当大地转置函子。

    意义深远的语义是user:false 表示的原因 system:false。另一方面,在局部语义中,M:G 表示M:G,仅此而已,我们更经常拥有代数性质。 在本地语义中,user:false 永远不会意味着 system:false

    再见

    【讨论】:

    • 我对此的看法是(:)/2 不应该被用户明确使用。也就是说,如果这样做了,则根本无法保证。所以有效地冒号是内部的东西。
    • 我想说任何明确的提及/操作都取决于实现。所以它不是直接禁止的,但你不能指望一个明确的结果。通过这种方式,分析可以发现有问题的案例;同时在例如实现SICStus 可以保持与现在一样。
    • 改变 SICStus 当前的做法是非常不现实的。定义一个“合理的子集”和方法绝对是一种更有前途的方法。
    • 您采取了哪些具体步骤来衡量这一点?我看不出 JITter 有什么不同
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-23
    • 1970-01-01
    • 1970-01-01
    • 2015-08-12
    相关资源
    最近更新 更多