更改参数顺序时,Prolog 统一被破坏

Posted

技术标签:

【中文标题】更改参数顺序时,Prolog 统一被破坏【英文标题】:Prolog unification broken when argument order is changed 【发布时间】:2021-02-13 05:47:27 【问题描述】:

我似乎无法理解这一点。考虑以下虚拟谓词:

foo(X, a) :- X < 10.
foo(X, b) :- X > 20.

咨询时:

?- foo(1, a).
true; 
false.

我不确定我是否完全理解选择点是如何创建的(也许是因为两个可能的foo 谓词处于一种 or 关系,而 Prolog 只是 尝试 em> 与两者统一?基于跟踪中的这一行:Redo: (24) test:foo(8, a) 和随后的失败,我想是这种情况),但真正让我困惑的是为什么它在参数顺序改变时起作用:

foo(a, X) :- X < 10.
foo(b, X) :- X > 20.
?- foo(a, 1).
true.

没有选择点。我在这里错过了什么?

【问题讨论】:

Prolog 通常会在第一个参数上“索引”。所以它知道b永远不会是一个很好的匹配,并跳过它。 好的,但是为什么它不知道在第一种情况下,即使X 可以匹配,b 仍然不匹配? 因为对于大多数 Prolog 解释器来说,这个索引只在 first 参数上完成。通常 Prolog 程序的编写是为了区分函子,第一个参数用于提高效率。 这也不是很重要(除了如果剩余的选择点开始在长时间运行/深度程序中影响性能 - 这确实很快)。只要findall(found, foo(1,a), All) 吐出一个解决方案[found],就很好。添加一个“!”或“-”,使 Prolog 处理器在保护测试后“提交”其子句:foo(X) :- guard(X),!,do_sth(X). 或(可能更清楚)foo(X) :- guard(X) -&gt; do_sth(X). 以增加确定性,同时确保 findall/3 收集的解决方案保持不变。 我明白了,这就是Prolog中的就像这样。 @DavidTonhofer 我为什么要这样做,而不是在我已经切割时使用 foo(1, a), !.?谢谢你们,请你们中的一个人也可以创建一个答案,以便我可以选择它作为解决方案吗? 【参考方案1】:

TL;DR:阅读您正在使用的 Prolog 的文档。注意“子句索引”或类似的东西。


您错过了您使用的任何 Prolog 实现都足够聪明,可以对第二个示例中的第一个参数进行索引。因此,当您提出查询 ?- foo(a, Something). 时,它永远不会考虑其他子句。

但这实际上是 Prolog 实现的问题,而不是 Prolog 作为一种语言的问题。也许有 Prologs 也可以避免第一个例子中的选择点。或者也许它提供了不同的机制来实现相同的目标。例如,SWI-Prolog(在其他 Prolog 中)有一个叫做“表格”的东西。有了它,你可以这样做:

:- table foo/2.

foo(X, a) :- X < 10.
foo(X, b) :- X > 20.

bar(a, X) :- X < 10.
bar(b, X) :- X > 20.


现在foo/2bar/2 都没有意外的选择点:

?- foo(1, a).
true.

?- bar(a, 1).
true.

【讨论】:

以上是关于更改参数顺序时,Prolog 统一被破坏的主要内容,如果未能解决你的问题,请参考以下文章

使用查询参数缓存获取的破坏图像

什么是统一术语顺序有关系吗?

Prolog 通配符:重复列表而不更改通配符值

Eclipse 在运行调试器时破坏了带有空格字符的程序参数

更改参数顺序的 Laravel 路由中出现 404 错误

Visual Studio:使用热键更改参数顺序