假设我们有以下谓词(这是来自Programming in Prolog的示例):
[F0] isInteger(0).
[F1] isInteger(X):- isInteger(Y), X is Y+1.
查询的第一个结果isInteger(R),标记位于F0,将返回R = 0
如果用户按下; ,标记放在F1,我们移动到subgoal(isInteger(Y),满意F0)和R = 1.
我理解上面的内容。现在我的问题是:
我正在寻找任何解释存在递归的回溯的教程,希望能够帮助我理解堆栈内容的图像。
提前谢谢你 苏珊
答案 0 :(得分:8)
通过使用图像来理解回溯和递归适用于非常小的示例,但它不能扩展到更大的程序。此外,通过单步执行程序,您很容易错过最有趣的属性。幸运的是,有更好的概念。我们举个例子isInteger/1
。
您的主要兴趣是确保您描述正确的事情。在这里,第二条规则最有趣。按箭头:-
的方向阅读。也就是说,从右到左:提供Y
是整数,X is Y+1
则X
也是整数。
然后,您可以估计在这种情况下无限的解决方案集。
下一个问题涉及谓词的终止属性。注意,它不能 - 实际上必须不 - 终止,如果它必须产生无限多的答案。另一方面,像isInteger(1)
这样的地面查询有一个或没有解决方案。因此,期望谓词终止于这种情况。但是,您的定义不会在此处终止!
为了更好地理解这一点,我将使用failure-slice。也就是说,我会在您的计划中插入 false
目标。如果生成的程序片段没有终止,则原始程序片段不会终止。
?- isInteger(1), falseisInteger(0) :- false. isInteger(X) :- isInteger(Y), false,X is Y+1.
只有很小一部分负责不终止!其余部分甚至根本没有查看X
的值。因此,您的程序将终止 never 。不管你怎么称呼它。
有关更多示例,请参阅failure-slice。
答案 1 :(得分:0)
在swish控制台中跟踪此内容:
% Handover to indenting predicate
isInteger(X) :- isInteger(X,0).
% As isInteger(), with printouts
isInteger(0,I) :- ws(I), format('0 reached\n').
isInteger(X,I) :- wrout('>', X,Y,I), ID is I+1, isInteger(Y,ID), wrout('<', X,Y,I), X is Y+1, wsucc(I).
% Writing out
wrout(C,X,Y,I) :-ws(I),format('~a X=',C),write(X),format(',Y='),write(Y),format('\n').
% Writing "success"
wsucc(I) :- ws(I),format('success\n').
% Indenting by 2*N underscores
ws(0).
ws(N) :- N>0, format('__'), ND is N-1, ws(ND).
通过? - isInteger(2).
检查2是否为整数(但不要为此调用Next或将发生永不停止的搜索!)
> X=2,Y=_G5707
__0 reached
< X=2,Y=0
__> X=_G5707,Y=_G6473
____0 reached
__< X=_G5707,Y=0
__success
< X=2,Y=1
success
true
使用?- isInteger(I)
0 reached
I = 0
“下一步”
> X=_G5328,Y=_G5926
__0 reached
< X=_G5328,Y=0
success
I = 1
“下一步”(请注意我们在缩进'__'处重新启动)
__> X=_G5926,Y=_G391
____0 reached
__< X=_G289,Y=0
__success
< X=_G257,Y=1
success
I = 2
“下一步”(请注意我们在缩进'____'处重新启动)
____> X=_G391,Y=_G3260
______0 reached
____< X=_G391,Y=0
____success
__< X=_G289,Y=1
__success
< X=_G257,Y=2
success
I = 3
非常好。
我将向当地团队解释。下面是整数枚举过程的示意图,其中包含一些“原始符号”。希望不言自明。