Prolog 太多回溯:为什么会有“回溯”;重做“;在这里

Prolog 太多回溯:为什么会有“回溯”;重做“;在这里,prolog,backtracking,successor-arithmetics,Prolog,Backtracking,Successor Arithmetics,我正在用Prolog做一个非常简单的练习,在跟踪中有一些东西我不明白。该程序是一个“大于”()的整数,表示为后续数: greater_than(succ(_), 0). greater_than(succ(A), succ(B)) :- greater_than(A, B). 我的问题:我不明白为什么请求大于(成功(成功(成功(0)),成功(0))会在以下跟踪中生成一个redo: [trace] ?- greater_than(succ(succ(succ(0))),succ(0)). C

我正在用Prolog做一个非常简单的练习,在跟踪中有一些东西我不明白。该程序是一个“大于”(
)的整数,表示为后续数:

greater_than(succ(_), 0).
greater_than(succ(A), succ(B)) :-
  greater_than(A, B).
我的问题:我不明白为什么请求
大于(成功(成功(成功(0)),成功(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
?我怎样才能避免它(当然,没有伤口)?


顺便说一句,在你提问之前:不,这不是什么家庭作业…

重做的原因是prolog无法推断(不检查它),如果遵循下一个子句,会有另一种解决方案。诚然,在这种情况下,它只是一个头部统一检查(这并不总是微不足道的),但它可能需要很多时间(甚至永远不会终止)

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

greater_than(succ(A), B):-
    B = succ(BI) ->
    greater_than(A,BI)
    ; B = 0.
并不是说这仍然需要额外的计算,而这可以通过cut避免


PS:我怀疑是否有人会认为这是一个家庭作业XD

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

更高版本的SWI没有这个问题。这可能与子句索引有关。这种行为会在没有索引的实现上出现,或者只在第一个参数上进行索引


但是很明显。SWI 5.6.56手册“最多可以索引4个参数”。所以它可能索引不止一个

这只是一个优化问题,一个给定的编译器可能有,也可能没有。好吧,一般来说,我想优化一个人的代码是一个合法的编程问题,即使一个人只在一种编译器上编码(这里是SWI)。然而,我刚刚更新了SWI,我甚至再也看不到这种行为,所以它确实是SWI的内部行为,我想这个问题真的不感兴趣。很抱歉出现噪音。我在我的SWI安装上尝试了你的代码,但它没有尝试任何重做。它不仅是编译器,也是它的版本。我看到你更新了它;也许这是一个非常旧的版本。是的,这肯定是一个版本问题(我不知道是哪一个,但从5.10.4开始就解决了)。我会发布一个答案,并尽快接受它(因为我的声誉,我必须等待8个小时),或者你可以这样做。不幸的是,这不是一个绿色削减<代码>大于(A,B)的工作原理不同。这里没有“额外的选择点”:只有一种方法可以在有
重做的子句头上执行统一。这个程序不需要删节,显然这只是SWI中的一个过渡错误,不是错误。选择点从左到右,从上到下。Prolog编译器甚至不必在回溯之前查看适合的子句下的子句。如果现在SWI对它进行了优化,这并不意味着以前它是一个bug。感谢您提供的详细信息。我确认这个问题似乎在5.10.4版中得到了解决(但也可能在一些早期版本中)。。。我不确定我是否喜欢这种语言的指定方式(以及编译器和解释器的预期行为)。