现代 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_check
:set_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
编辑: 本题假定您启用了发生检查。 不是关于
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_check
:set_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