更改参数顺序时,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) -> 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/2
和bar/2
都没有意外的选择点:
?- foo(1, a).
true.
?- bar(a, 1).
true.
【讨论】:
以上是关于更改参数顺序时,Prolog 统一被破坏的主要内容,如果未能解决你的问题,请参考以下文章