考虑这个简单的Prolog程序:
nat(0).
nat(s(X)) :- nat(X).
plus(X, 0, X) :- nat(X).
plus(X, s(Y), s(Z)) :- nat(X), nat(Y), nat(Z), plus(X, Y, Z).
fib(0, 0).
fib(s(0), s(0)).
fib(s(s(K)), Z) :- fib(s(K), Y), fib(K, X), plus(X, Y, Z).
我已经测试过plus
,并且似乎可以正常工作。让我们看看fib
是否也可以正常工作...
?- fib(0, 0).
true.
?- fib(s(0), s(0)).
true ;
false.
?- fib(s(s(0)), s(0)).
true ;
false.
?- fib(s(s(s(0))), s(s(0))).
true ;
ERROR: Out of global stack
一切顺利,直到我想打印第三个数字,恰好是2!
我知道以这种方式模拟Peano算术远非有效,而且这里使用的指数算法不是最优的,尽管如此,我拒绝相信在我只计算时就出现了性能问题。第三个数字。因此,我的程序肯定会循环,因此是错误的。
...为什么循环?使其停止循环需要什么?
答案 0 :(得分:1)
简短答案:之所以循环,是因为 plus(0, s(0), X).
将产生true
,然后循环。
如果我们看一下trace
,我们会看到:
[trace] ?- fib(s(s(s(0))), s(s(0))).
Call: (8) fib(s(s(s(0))), s(s(0))) ? creep
Call: (9) fib(s(s(0)), _902) ? creep
Call: (10) fib(s(0), _906) ? creep
Exit: (10) fib(s(0), s(0)) ? creep
Call: (10) fib(0, _910) ? creep
Exit: (10) fib(0, 0) ? creep
Call: (10) plus(0, s(0), _912) ? creep
...
Exit: (9) plus(s(0), s(0), s(s(0))) ? creep
Exit: (8) fib(s(s(s(0))), s(s(0))) ? creep
true .
但是口译员在该谓词中回溯,旨在寻找更多解决方案。这是由于您的nat(Z)
每次都给出一个下一个值,然后解释器调用plus(X, Y, Z)
来检查是否匹配,但是每次失败都如此。
当我们跟踪plus(0, s(0), X)
时,我们可以看到:
[trace] ?- plus(0, s(0), X).
Call: (8) plus(0, s(0), _676) ? creep
Call: (9) nat(0) ? creep
Exit: (9) nat(0) ? creep
Call: (9) nat(0) ? creep
Exit: (9) nat(0) ? creep
Call: (9) nat(_884) ? creep
Exit: (9) nat(0) ? creep
Call: (9) plus(0, 0, 0) ? creep
Call: (10) nat(0) ? creep
Exit: (10) nat(0) ? creep
Exit: (9) plus(0, 0, 0) ? creep
Exit: (8) plus(0, s(0), s(0)) ? creep
X = s(0) ;
Redo: (9) plus(0, 0, 0) ? creep
Fail: (9) plus(0, 0, 0) ? creep
Redo: (9) nat(_884) ? creep
Call: (10) nat(_888) ? creep
Exit: (10) nat(0) ? creep
Exit: (9) nat(s(0)) ? creep
Call: (9) plus(0, 0, s(0)) ? creep
Fail: (9) plus(0, 0, s(0)) ? creep
Redo: (10) nat(_888) ? creep
当然nat(Z)
成功之后,plus(0, s(0), X)
提出的答案都不会成功。
但是无论如何,没有理由调用nat(Z)
,因为最终递归调用将落入将验证nat(X)
的基本情况下,因此我们可以像这样实现它:
plus(X, 0, X) :- nat(X).
plus(X, s(Y), s(Z)) :- plus(X, Y, Z).
在 first 参数上使用不同的模式通常也更有效:
plus(0, X, X) :- nat(X).
plus(s(X), Y, s(Z)) :- plus(X, Y, Z).