我在OS X 7上使用SWI-Prolog版本6.4.1,并且遇到谓词的以下意外行为current_functor/2:
鉴于事实
p(a).
q.
Run Code Online (Sandbox Code Playgroud)
我得到了这些查询的答案:
?- current_functor(p, Y).
Y = 1
?- current_functor(q, Y).
false.
?- current_functor(q, 0).
true.
Run Code Online (Sandbox Code Playgroud)
第二个和第三个查询不仅看起来公然不一致,而且第二个查询的失败似乎与SWI-Prolog参考手册不一致,后者描述current_functor/2如下:
current_functor(?Name,?Arity)连续使用名称和Arity统一Name,并使用系统已知的仿函数.
任何人都可以帮助我理解为什么谓词以这种方式运作?
编辑:
在解决我测试谓词是否已被定义的特定问题方面,包括某些0-arity,我最终遵循了错误的建议并编写了以下内容:
current_pred(P) :-
current_predicate(P/_).
Run Code Online (Sandbox Code Playgroud)
长话短说:不要!
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).
Run Code Online (Sandbox Code Playgroud)