我是Prolog的初学者,我正在寻找一种方法来反转此代码的输出。
fib(N, F) :- fib(N, 0, [1], F).
fib(0, _, A, A).
fib(N, A, [B|Bs], F) :- N1 is N - 1, Sum is A + B, fib(N1, B, [Sum,B|Bs], F).
代码计算N
值的斐波纳契数,并将结果打印在F
。
例如fib(4,X).
生成X=[5,3,2,1,1]
。我想要的是X=[1,1,2,3,5]
(反向输出)。
我似乎无法将其带入此格式,并保留其尾递归属性。
感谢您的帮助
答案 0 :(得分:0)
如果您只想在结尾处反转列表,请使用reverse/2
:
fib(N, F) :- fib(N, 0, [1], FRev), reverse(FRev, F).
如果要以相反的顺序构建列表,则必须重新考虑这些子句。一种解决方案是使用last/2
和append/3
将新元素放在累加器的末尾,而不是放在它前面。
在返回第一个解决方案后,Prolog尝试找到第二个解决方案,您可能会收到错误:
?- fib(5, F).
F = [8, 5, 3, 2, 1, 1] ;
ERROR: Out of global stack
这种情况发生的原因是因为目标fib(0, ...)
Prolog使用第一个规则,但创建了一个选择点,它稍后会回溯到它。从那时起,堆栈中充满了目标:fib(-1,...)
,fib(-2,...)
等。这些都不会满足。您应该在fib/4
的第一个子句中放置一个cut运算符:
fib(0, _, A, A):-!.
因此不会尝试使用第二条规则重新fib(0,...)
。
?- fib(5, F).
F = [8, 5, 3, 2, 1, 1].