5

我在 OS X 7 上使用 SWI-Prolog 版本 6.4.1,并且在使用谓词时遇到以下意外行为current_functor/2

鉴于事实

p(a).
q.

我得到这些查询的答案:

?- current_functor(p, Y).
Y = 1 

?- current_functor(q, Y).
false.

?- current_functor(q, 0).
true.

不仅第二个和第三个查询看起来明显不一致,而且第二个查询的失败似乎与 SWI-Prolog 参考手册不一致,其描述current_functor/2如下:

current_functor(?Name, ?Arity) 依次将 Name 与名称统一,将 Arity 与系统已知的函子的数量统一。

谁能帮我理解为什么谓词以这种方式起作用?

编辑:

为了解决我测试谓词是否已定义的特殊问题,包括某些 0-arity 的,我最终遵循了 false 的建议并编写了以下内容:

current_pred(P) :-
    current_predicate(P/_).
4

2 回答 2

4

我认为 pl-funct.c 的第 391 行可能存在错误。那行读

if ( fd && fd->arity > 0 && (!nm || nm == fd->name) )

现在我将尝试纠正fd->arity >= 0并测试...

编辑显然它有效:

1 ?- [user].
yy.
|: 
% user://1 compiled 0.00 sec, 2 clauses
true.

2 ?- current_functor(yy,X).
X = 0 ;
false.

我会尝试提交,但我认为我没有 git 访问完整源代码的权限......

确实编辑,git 拒绝接受我的更改...我将报告 SWI-Prolog 邮件列表。

于 2013-10-28T19:44:17.270 回答
4

TL;DR:不要!

current_functor/2是一个特定于 SWI 的内置谓词,您在其他任何地方都找不到(除了历史上唯一相关的 DECsystem 10)。这个谓词的原因与 SWI 中函子的具体表示有关。简而言之,SWI 需要在使用之前注册每个函子。(在此之前它需要注册相关的原子。)如果不再使用仿函数会发生什么?那么它是否仍然存在?这个资源垃圾收集了吗?

回答你的问题: current_functor/2只会对函子成功。没有元数为 0 的函子。元数为 0 的项称为原子,处理方式不同。

在任何情况下,您都将编写依赖于由一个人维护的单个实现的代码。对于更大的项目来说,这不是一个非常安全的选择。

其他 Prolog 系统的工作方式不同。他们也需要注册原子,但随后他们可以构造任何函子,而max_arity无需使用更多的全局资源。出于这个原因,许多系统提供current_atom/1.

但即使是那个谓词也是不明确的。毕竟,原子仍然存在意味着什么?优化编译器可以删除一个原子,从而改变它的含义吗?它是一种检查应用程序使用的一些看起来无害的查询代码的机密原子的方法吗?

这一切真的是一罐蠕虫。不惜一切代价避免它们。也许current_predicate改用。


说了这么多,如果您仍然认为自己需要它,请执行以下操作:

current_f(F, A) :-
   current_functor(F, A).
current_f(F, 0) :-
   current_atom(F).
于 2013-10-28T21:18:12.490 回答