现代 Prolog 编译器是否会在安全时自动优化发生检查?

Do modern Prolog compilers optimize away the occurs check automatically, when it's safe?

编辑: 本题假定您启用了发生检查。 不是关于

30 年前有很多论文关于在安全时自动优化发生检查(大约 90% 的谓词,在典型的代码库中)。提出了不同的算法。现代 Prolog 编译器(例如 SWI Prolog)是否会做类似的事情(当发生检查打开时)?他们喜欢什么算法?

例如,他们会在编译如下谓词时删除发生检查吗:

less(0, s(_)).
less(s(X), s(Y)) :- less(X, Y).

(来自下面的讨论

SWI Prolog 不会打开发生检查,除非您特别要求它:

  • 通过在本地使用 unify_with_occurs_check/2 而不是 =。 (请注意,这意味着 head 统一不受影响,即仍然在没有发生检查的情况下运行 - 我认为?)
  • 通过设置标志occurs_checkset_prolog_flag(occurs_check,true)
  • ,通过打开发生检查全局

这是个问题吗?我不这么认为。

考虑在其他编程语言中使用断言的相关案例(甚至在 Prolog 中:assertion/1,我衷心推荐)。

当您进行开发时,您将“开启”这些功能以在运行时以一些 CPU 成本验证约束。一旦您确定您的程序可以工作(通过构建、生产和测试),您将“关闭它们”。您的程序和任何调用者(可能是恶意的、混淆的或错误的)之间的接口可能仍然受到 must_be/2 检查的保护,以便强制执行接口契约。

出现检查的情况类似:如果您怀疑循环数据结构可能出现并导致问题,请打开 'occurs check'。对您的程序进行编码,以便一切正常(并且您确定它可以正常工作,最好通过构造和证明)。然后再关掉它。

有多种优化可以在发生检查标志设置为“真”时优化掉发生检查。这对于在常见情况下实现合理的统一是必要的。一个典型的优化是检测磁头的线性度:

linear(Head) :-
   term_variables(Head, Vars),
   term_singletons(Head, Singletons),
   Vars == Singletons.

在这种情况下,调用子句时可以省略发生检查。我们可以对 less/2 的例子做头部是否线性的测试。原来两个头都是线性的:

?- linear(less(0, s(_))).
true.

?- linear(less(s(X), s(Y))).
true.

因此,Prolog 系统可以完全省略对谓词 less/2 的发生检查,但仍会产生合理的统一。例如,在检查中间代码时,可以在 Jekejeke Prolog 中看到这种优化。使用指令unify_linear:

?- vm_list(less/2).

less(0, s(A)).
  0  unify_linear _0, 0
  1  unify_linear _1, s(A)
less(s(X), s(Y)) :-
   less(X, Y).
  0  unify_linear _0, s(X)
  1  unify_linear _1, s(Y)
  2  goal_last less(X, Y)

与指令unify_term相反,指令unify_linear不执行发生检查,即使发生检查标志设置为真。

日图查达;戴维·A·普莱斯特德 (1994)。 “未在 prolog 中发生检查的统一的正确性”。逻辑编程杂志。 18 (2): 99–122。 doi:10.1016/0743-1066(94)90048-5.

什么也很流行,在变量内部使用区分,比如“新鲜”和“陈旧”变量。 “新鲜”变量通常不需要发生检查。

可以动态区分。下面是一些结果,动态区分(“新鲜度”)也可以结合一些静态分析(“线性”):

上图显示了基于引用计数的启发式方法的结果。下面的论文讨论了使用一位,即将变量标记为 UNBOUND 或 NEW_UNBOUND.

重温发生检查问题 - 啤酒,1988
https://core.ac.uk/download/pdf/82747799.pdf