【问题标题】:What's the SLD tree for this query?这个查询的 SLD 树是什么?
【发布时间】:2012-10-31 16:43:38
【问题描述】:

让我们考虑以下 Prolog 程序(来自“The Art of Prolog”):

natural_number(0).
natural_number(s(X)) :- natural_number(X).

plus(X, 0, X) :- natural_number(X).
plus(X, s(Y), s(Z)) :- plus(X, Y, Z).

和查询:

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

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

【问题讨论】:

  • 您将plus/3的第一个和第二个参数与Prolog艺术的程序3.3进行了比较。但是就这样吧……

标签: prolog successor-arithmetics prolog-cut


【解决方案1】:

许多 Prolog 系统并不像我们期望的那样智能。这有几个原因,主要是因为实施者的权衡选择。对某些人来说似乎很重要的事情对其他人来说可能并不那么重要。

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

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

?-加(s(s(s(0))), s(0), Z)。 Z = s(s(s(s(0)))) ; 错误的。 ?- call_semidet(plus(s(s(s(s(0)))), s(0), Z))。 Z = s(s(s(s(0))))。

但您也可以从更乐观的方面看到这一点:现代顶层(如 SWI 中的顶层)确实会在有剩余选择点时向您显示。所以你可以考虑一些对策,比如call_semidet/1

以下是一些相关的答案:

【讨论】:

    【解决方案2】:

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

    现在 SWI-Prolog 存在一个已知限制。虽然它确实 多参数索引,它不做选择点消除 对于非第一个参数索引 级联索引。方法 它只选择一个论点,但没有进一步。有一些 执行多参数索引和级联索引的 Prolog 系统。 例如在Jekejeke Prolog 我们没有No/false:

    再见

    P.S.:最新版本的 Jekejeke Prolog 甚至没有 字面上级联,因为它检测到第一个参数索引 没有敏感性。因此,虽然它为 由于实际调用模式,第一个参数,它跳过 第一个参数索引并且不使用它,并且仅使用 第二个论点。跳过会带来一点速度。 :-)

    通过dump/1 命令可以看到跳过 开发环境版本:

    ?- 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=0arg=1 索引。我们可能仍将其称为启发式级联 因为单个查询会导致多个索引,但它们 没有真正的级联形状。

    【讨论】:

    • 如果我不明白,你是说,如果一个术语与规则头的函子和第一个参数匹配,SWI Prolog 将规则视为(可能)匹配并为它。我说的对吗?
    • @CookieMonster:
       允许文本中的 
    • @CookieMonster:所以,如果我理解正确的话,Prolog 实现并不总是计算其头部与给定谓词匹配的确切子句集,只是为了提高效率。确实,通过交换加号规则的声明顺序,我可以看到SWI在各个层级都创建了一个选择点。我想我明白了。谢谢大家。
    【解决方案3】:

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

    【讨论】:

    • trace 的问题是它在大多数 Prolog 系统中添加了选择点(这里 SWI Prolog 是一个例外,这意味着您也看不到所有端口用于确定性执行),因此该方法不是通常可以可靠地解释为什么某些事情不是确定性的。
    • @CookieMonster:是不是在这种特殊情况下?在查询和跟踪中只有一个待处理的选择点,所以我认为是这样。
    • 查克是对的。我只想指出,在某些 Prolog 系统中,跟踪模式可能会改变选择点消除行为。这是因为跟踪有时会在后台实现,将每个目标 G 替换为 (port(call); port(fail), fail), G, (port(exit); port(redo), fail),这增加了选择指向并改变了决定论的传播。
    • @Cookie Monster:如果操作正确,我预计您所展示的转换不会改变行为。否则,这样的调试工具就没什么用了。
    • 是的,留下选择点的调试工具会减慢执行速度,或者占用内存空间。这在许多早期的 Prolog 系统中都可以看到。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-26
    • 2014-09-17
    • 1970-01-01
    • 2011-03-12
    • 2016-04-28
    • 2014-10-01
    相关资源
    最近更新 更多