太多的回溯:为什么这里有“重做”?

时间:2012-08-30 07:38:34

标签: prolog backtracking successor-arithmetics

我在Prolog做了一个非常简单的练习,并且我在跟踪中有一些我不理解的东西。该程序是一个“大于”(>)的整数,表示为后继者:

greater_than(succ(_), 0).
greater_than(succ(A), succ(B)) :-
  greater_than(A, B).

我的问题:我不明白为什么请求greater_than(succ(succ(succ(0))),succ(0))在以下跟踪中生成redo

[trace] ?- greater_than(succ(succ(succ(0))),succ(0)).
Call: (6) greater_than(succ(succ(succ(0))), succ(0)) ? creep
Call: (7) greater_than(succ(succ(0)), 0) ? creep
Exit: (7) greater_than(succ(succ(0)), 0) ? creep
Exit: (6) greater_than(succ(succ(succ(0))), succ(0)) ? creep
true ;
Redo: (7) greater_than(succ(succ(0)), 0) ? creep
Fail: (7) greater_than(succ(succ(0)), 0) ? creep
Fail: (6) greater_than(succ(succ(succ(0))), succ(0)) ? creep
false. 

为什么redo在这里?我怎样才能避免它(当然没有削减)?

顺便提一下,在你问:不,这不是某种功课......

2 个答案:

答案 0 :(得分:1)

好的,所以这是一个编译器优化,给定的编译器/版本组合可能有也可能没有。

更新版本的SWI没有此问题。它可能与子句索引有关。这种行为将在没有索引的实现上看到,或仅在第一个参数上的索引上看到。

但显然,"SWI-Prolog provides `just-in-time' indexing over multiple arguments"。 SWI 5.6.56手册states表示“最多可以索引4个参数”。所以它可能索引不止一个。

答案 1 :(得分:0)

如果通过遵循下一条款,将有一个替代解决方案,那么有一个重做是prolog不能推断(不检查它)。是的,在这种情况下,它只是一个头部统一检查(不是这总是微不足道)但它可能需要花费很多时间(甚至永远不会终止)。

现在,这正是你应该使用cut的地方:你知道额外的选择点不会产生解决方案(因此你不会改变语义 - 绿色切割)。或者(但它主要是覆盖切割的语法糖)你可以使用if-then-else:

greater_than(succ(A), B):-
    B = succ(BI) ->
    greater_than(A,BI)
    ; B = 0.

并不是说这仍然可以进行额外的计算,而这些计算可以通过削减来避免。

PS:我怀疑有人会认为这是作业XD