Prolog Peano算法中的Stackoverflow

时间:2013-09-27 11:16:21

标签: prolog stack-overflow failure-slice successor-arithmetics

我正在写一些Peano算法来更好地学习Prolog。以下是我提出的代码,它似乎与我在网上其他地方看到的相同:

add(X,z,X).
add(X,s(Y),s(Z)) :- add(X,Y,Z).
mult(_,z,z).
mult(X,s(Y),W) :- mult(X,Y,Z), add(X,Z,W).

但是,如果我尝试进行简单的查询,例如0的除数对,我会遇到问题:

| ?- mult(X,Y,z).

Y = z ? ;

X = z
Y = s(z) ? ;

X = z
Y = s(s(z)) ? ;

X = z
Y = s(s(s(z))) ? ;

Fatal Error: global stack overflow (size: 32768 Kb, reached: 32765 Kb, environment variable used: GLOBALSZ)

它真的让我感到困惑,至于它如何能够一直到Y = 3,而不是Y = 4

2 个答案:

答案 0 :(得分:3)

发生堆栈溢出是因为对于您的查询,最终使用变量作为中间参数调用谓词add/3。当你回溯到它时,你会得到一个导致堆栈溢出的循环。考虑通话add(X,Y,Z)。第一个子句为您提供了第一个解决方案add(X,z,X)。但是,在回溯时,当你使用第二个子句时,你用add(X,s(Y),s(Z))统一你的查询并递归调用add(X,Y,Z),回到你开始的地方(记住,中间参数没有实例化,所以{{1在Y中也不会在调用中实例化。如上所示,你能够得到前四个解决方案,这要归功于两个谓词的基本情况。当使用那些基础子句时(在回溯中已经筋疲力尽,你进入我刚才解释的循环。

尝试添加以下子句作为s(Y)谓词的第一个子句:

add/3

重试您将获得的查询(希望您能快速使用add(X,Y,Z) :- write('Called: '), writeq(add(X,Y,Z)), nl, fail. ):

Control-C

希望这有帮助。

答案 1 :(得分:1)

我知道这是一篇非常古老的帖子,但我刚开始学习Prolog并发现这个问题引人入胜。所以这是我的两分钱。

我注意到如果你改变你的规则

mult(X,s(Y),W) :- mult(X,Y,Z), add(X,Z,W).

分离

mult(X,s(Y),W) :- mult(X,Y,Z); add(X,Z,W).

并运行相同的查询

?- mult(X,Y,z).

你会得到一些结果,但是你可以看到SWI Prolog解释器在一点之后没有显示太多细节:

?- mult(X,Y,z).
Y = z ;
Y = s(z) ;
Y = s(s(z)) ;
Y = s(s(s(z))) ;
Y = s(s(s(s(z)))) ;
Y = s(s(s(s(s(z))))) ;
Y = s(s(s(s(s(s(z)))))) ;
Y = s(s(s(s(s(s(s(z))))))) ;
Y = s(s(s(s(s(s(s(s(z)))))))) ;
Y = s(s(s(s(s(s(s(s(s(z))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) ;
Y = s(s(s(s(s(s(s(s(s(s(...)))))))))) .

在Gnu Prolog中做同样的事情看起来好多了,轻轻地说:

| ?- mult(X,Y,z).

Y = z ? ;

Y = s(z) ? ;

Y = s(s(z)) ? ;

Y = s(s(s(z))) ? ;

Y = s(s(s(s(z)))) ? ;

Y = s(s(s(s(s(z))))) ? ;

Y = s(s(s(s(s(s(z)))))) ? ;

Y = s(s(s(s(s(s(s(z))))))) ? ;

Y = s(s(s(s(s(s(s(s(z)))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(z))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(z)))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(s(z))))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(s(s(z)))))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(s(s(s(z))))))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(s(s(s(s(z)))))))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(z))))))))))))))) ? ;

Y = s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(z)))))))))))))))) ? ;   
...

在SWI Prolog(和GNU Prolog)中,您可以调用调试器,这可以更好地说明Paulo Moura关于原始问题的优秀理论分析:

 ?- trace, mult(X,Y,z).

正如您将看到的,它似乎永远在运行,因此可以解释堆栈溢出。追踪追踪here的结果,尽在其中。您也可以通过运行上面的跟踪来跟踪browser上的无限循环。