countdown(0, Y).
countdown(X, Y):-
append(Y, X, Y),
Y is Y-1,
countdown(X, Y).
因此,对于这个节目,我正在尝试制作一个倒计时程序,它将Y取一个数字并从3到0倒计时,同时将每个数字添加到列表中,以便倒计时(3,Y)。应该产生结果Y=[3,2,1].
当我运行这个时,我似乎无法结束递归,我想知道是否有人可以帮助我?
我似乎无法获得此代码以获得任何帮助?我似乎离开了全局堆栈,所以我不明白如何结束递归。
答案 0 :(得分:0)
您的代码中存在多个错误:
你可以这样做:
countdown(X, L):-
findall(Y, between(1, X, Y), R),
reverse(R, L).
between/3
将为您提供从1到X的每个数字(回溯)。因此findall/3
可以收集所有数字。这会给你升序,所以我们reverse/2
得到降序。
如果你想以递归方式编码自己:
countdown(X, [X|Z]):-
X > 1,
Y is X-1,
countdown(Y, Z).
countdown(1, [1]).
基本情况(第2条)规定,数字1会产生一个包含第1项的列表。
Recursive clause(first clause)声明如果X大于1,那么输出列表应该包含附加了递归调用结果的X.
答案 1 :(得分:0)
您的原始代码
countdown( 0 , Y ) .
countdown( X , Y ) :-
append(Y, X, Y),
Y is Y-1,
countdown(X, Y).
有一些问题:
countdown(0,Y).
并未将Y
与任何内容统一起来。Y is Y-1
正在尝试将Y
与Y-1
的值统一起来。在Prolog中,变量一旦绑定到一个值,就不再变量了:它们就变成了统一的变量。因此,如果Y
是数值,则Y is Y-1
将失败。如果Y
是一个变量,根据您的Prolog实现,它将失败或抛出错误。append(Y,X,Y)
能够神奇地制作一个列表。一个常见的Prolog习语是在你递归时建立列表。列表的尾部在每次递归时传递,列表本身不完整。 完整列表是最后一项是原子[]
的列表,表示空列表。在以这种方式构建列表时,最后一项是始终一个变量,并且列表不会完成,直到递归成功为止。因此,简单的解决方案就是在递归时构建列表:
countdown( 0 , [] ) . % The special case.
countdown( N , [N|Ns] ) :- % The general case: to count down from N...
N > 0 , % - N must be greater than 0.
N1 is N-1 , % - decrement N
countdown(N1,Ns) % - recurse down, with the original N prepended to the [incomplete] result list.
. % Easy!
您可能会注意到countdown(0,L)
会成功生成L = []
。您可以通过更改我们的规则来修复它。特殊(终止)情况略有不同,一般情况强制执行N > 1
的下限而不是N > 0
。
countdown( 1 , [1] ) .
countdown( N , [N|Ns] ) :-
N > 1 ,
N1 is N-1 ,
countdown(N1,Ns)
.
如果真的想要使用append/3
,你可以。它介绍了另一种常见的Prolog习语: helper 谓词的概念,它承载状态并完成所有工作。辅助谓词通常与" public"相同。谓词,具有更高的统一性。像这样:
countdown(N,L) :- % to count down from N to 1...
N > 0 , % - N must first be greater than 0,
countdown(N,[],L) % - then, we just invoke the helper with its accumulator seeded as the empty list
. % Easy!
在这里,countdown/2
是我们的公共谓词。它调用countdown/3
来完成工作。附加参数带有所需的状态。那个助手看起来像这样:
countdown( 0 , L , L ) . % once the countdown is complete, unify the accumulator with the result list
countdown( N , T , L ) . % otherwise...
N > 0 , % - if N is greater than 0
N1 is N-1 , % - decrement N
append(T,[N],T1) , % - append N to the accumulator (note that append/3 requires lists)
countdown(N1,T1,L) % - and recurse down.
. %
你可能会注意到使用这样的append/3
意味着它会在每次调用时迭代累加器,从而得到O(N 2 )性能而不是所需的O(N)性能
避免这种情况的一种方法是以相反的顺序构建列表,并在最后反转它。这只需要在列表上进行一次额外的传递,这意味着您可以获得O(2N)性能而不是O(N 2 )性能。这给了你这个帮手:
countdown( 0 , T , L ) :- % once the countdown is complete,
reverse(T,L) % reverse the accumulator and unify it with the result list
. %
countdown( N , T , L ) :- % otherwise...
N > 0 , % - if N is greater than 0
N1 is N-1 , % - decrement N
append(T,[N],T1) , % - append N to the accumulator (note that append/3 requires lists)
countdown(N1,T1,L) % - and recurse down.
. %