我在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(?姓名,?Arity) 使用名称和Arity将Name与系统已知的仿函数联合起来。
任何人都可以帮助我理解为什么谓词以这种方式运作吗?
修改
在解决我测试谓词是否已被定义的特定问题方面,包括某些0-arity,我最后遵循了错误的建议并撰写了以下内容:
current_pred(P) :-
current_predicate(P/_).
答案 0 :(得分: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邮件列表。
答案 1 :(得分:4)
TL; DR:不要!
current_functor/2
是一个特定于SWI的内置谓词,您将无法找到其他谓词(除了历史上唯一相关的DECsystem 10)。这个谓词的原因与SWI中仿函数的具体表示有关。简而言之,SWI需要在使用之前注册每个仿函数。 (在此之前,它需要注册相关原子。)如果不再使用仿函数会发生什么?它会不会存在?是否收集了此资源垃圾?
要回答您的问题: current_functor/2
只能成功使用仿函数。没有arity 0的仿函数。具有arity 0的术语称为原子,处理方式不同。
在任何情况下,您都将编写依赖于由单个人维护的单个实现的代码。对于一个更大的项目来说,这不是一个非常安全的选择。
其他Prolog系统的工作方式不同。他们也需要注册原子,但是他们可以在不使用其他全局资源的情况下构造任何最近max_arity
的函子。因此,许多系统提供current_atom/1
。
但即使是那个非常谓词也是如此。毕竟,原子仍然存在意味着什么?优化编译器是否可以删除原子从而改变其含义?它是一种通过一些看似无害的查询代码来检查应用程序使用的机密原子的手段吗?
这一切都是一堆蠕虫。不惜一切代价避免它们。也许改为使用current_predicate
。
所有这一切,如果您仍然相信您需要它,请执行:
current_f(F, A) :-
current_functor(F, A).
current_f(F, 0) :-
current_atom(F).