什么';此查询的SLD树是什么? 让我们考虑下面的Prolog程序(来自Prolog的艺术):

什么';此查询的SLD树是什么? 让我们考虑下面的Prolog程序(来自Prolog的艺术):,prolog,successor-arithmetics,prolog-cut,Prolog,Successor Arithmetics,Prolog Cut,以及查询: ?- plus(s(s(s(0))), s(0), Z). SICStus和SWI都会生成预期的Z=s(s(s(s(0))答案,但向用户查询下一个答案(正确的no/false答案)。但是,我无法理解为什么在找到唯一目标后SLD树中会有一个打开的分支。我尝试在SICStus和SWI下进行调试,但我还不能真正解释结果。我只能说,就我所能理解的,两者都回到了加上(s(s(s(0)),0,Z2)。有人能帮我理解这种行为吗?对我们来说,很明显,加号的两个子句是“析取”的。我们可以这样说,因为

以及查询:

?- plus(s(s(s(0))), s(0), Z).

SICStus和SWI都会生成预期的
Z=s(s(s(s(0))
答案,但向用户查询下一个答案(正确的
no
/
false
答案)。但是,我无法理解为什么在找到唯一目标后SLD树中会有一个打开的分支。我尝试在SICStus和SWI下进行调试,但我还不能真正解释结果。我只能说,就我所能理解的,两者都回到了
加上(s(s(s(0)),0,Z2)
。有人能帮我理解这种行为吗?

对我们来说,很明显,加号的两个子句是“析取”的。我们可以这样说,因为我们知道
0\=s(Y)
。但是,(我认为)这种分析通常是令人望而却步的,而PROlog则认为这样的分支仍有待证明:这里有一个跟踪,表明在找到第一个解决方案之后,调用(7)仍然是“开放”的。

问题与SLD树没有直接关系,因为Prolog 系统不会像以前那样以前瞻的方式构建SLD树 你描述它。但是在某些Prolog中发现了一些优化 系统本质上具有这种效果,改变了盲目的野蛮人 强制头部匹配。即索引和选择点消除

现在已知SWI Prolog有一个限制。尽管如此 多参数索引,它不做选择点消除 对于非第一个参数索引,使用级联索引。方法 它只选择了一个论点,但没有进一步的论证。有一些 执行多参数索引和级联索引的Prolog系统。 例如,在中,我们没有No/false:

再见

注:最新版本的Jekejeke Prolog甚至没有 字面上说是级联,因为它检测到第一个参数索引 没有敏感性。因此,尽管它为 由于实际的调用模式,第一个参数跳过 第一个参数索引,不使用它,只使用 第二个论点。跳过可以提高一点速度。:-)

通过 开发环境版本:

?- dump(plus/3).
-------- plus/3 ---------
length=2
arg=0
  =length=2
arg=1
  0=length=1
  s=length=1
Yes
因此,它没有降级到
arg=0
,而是构建了
arg=1
在那里建立索引,而是并行构建
arg=0
arg=1
索引。我们仍然可以称之为启发式级联 因为单个查询会导致多个索引,但是
没有真正的级联形状。

许多Prolog系统没有我们期望的那么智能。这有几个原因,主要是因为实现者的权衡选择。对某些人来说重要的东西对其他人来说可能不那么重要

因此,这些剩余的选择点可能会及时累积,并阻止释放辅助数据。例如,当您想阅读一长串文本时。一个列表太长,无法立即放入内存,但仍然可以使用
库(pio)
高效处理

如果您只需要一个答案,您可以使用
call_semidet/1
来确定答案。 有关其定义和用例,请参见

?- plus(s(s(s(0))), s(0), Z). Z = s(s(s(s(0)))) ; false. ?- call_semidet(plus(s(s(s(0))), s(0), Z)). Z = s(s(s(s(0)))). ?-加(s(s(0)),s(0),Z)。 Z=s(s(s(0)); 错。 ?调用_semidet(加上(s(s(0)),s(0),Z))。 Z=s(s(s(0)))。 但你也可以从一个更乐观的角度来看待它:现代顶级水平(比如SWI中的顶级水平)确实会告诉你什么时候有剩余的选秀点。因此,您可以考虑一些对策,如:代码> Call SimiDt/ 1 以下是一些相关的答案:


跟踪的问题是,它在大多数Prolog系统中增加了选择点(SWI Prolog在这里是个例外,也意味着你看不到所有用于确定性执行的端口),因此该方法通常不可靠,无法解释为什么某些东西是不确定性的。@CookieMonster:是在这种特殊情况下吗?查询和跟踪中都只有一个挂起的选择点,所以我假设是这样的。我只想指出,在某些Prolog系统中,跟踪模式可能会改变选择点消除行为。这是因为跟踪有时是在后台实现的,用(端口(调用);端口(失败),失败),G,(端口(退出);端口(重做),失败来替换每个目标G,这会增加选择点并改变决定论的传播。@Cookie Monster:如果做得正确,我希望您显示的转换的行为不会发生任何变化。是的,留下选择点的调试工具会降低执行速度,或者消耗内存空间。这在很多早期的Prolog系统中都可以看到。如果我不理解坏,你会说,如果一个词与规则头的函子和第一个参数相匹配,则SWI PROLO将该规则视为(潜在的)匹配,并为它创建一个选择点。我说的对吗?是的,这并不是因为选择点并没有被消除,而是因为索引并没有级联。也就是说,它在第一个参数中看到s(s(0)),然后使用第一个参数索引,它有两个条目。如果在第二个参数中也使用0,则可能会进一步减少子句集。@Pietro:选择点是在子句头匹配且当前位置的子句集具有更多条目时创建的。索引有助于减少子句集,从而防止创建选择点。@false:不,这并不简单。我选择块,然后按下{}按钮,它为我进行调整。我不必打字。按{}按钮更简单。你应该试试看。你也可以使用Ctrl-K。@false:但我不经常使用它。。。你从我这里看不到多少内联
。这也适用于……与Prolog艺术的程序3.3相比,您交换了
plus/3
的第一个和第二个参数。但是就这样吧。。。 ?- plus(s(s(s(0))), s(0), Z). Z = s(s(s(s(0)))) ; false. ?- call_semidet(plus(s(s(s(0))), s(0), Z)). Z = s(s(s(s(0)))).