我想编写为给定 N 生成斐波那契数列的谓词。
fibon(6, X) -> X = [0,1,1,2,3,5].
Run Code Online (Sandbox Code Playgroud)
我有一个谓词来生成斐波那契数列的第 N 个元素:
fib(0, 0).
fib(1, 1).
fib(N, F) :-
N > 1,
N1 is N - 1,
N2 is N - 2,
fib(N1, F1),
fib(N2, F2),
F is F1 + F2.
Run Code Online (Sandbox Code Playgroud)
我尝试编写 fibon/2,但它不起作用:
fibon(N, [H|T]) :-
fib(N, H),
N1 is N - 1,
fibon(N1, T).
Run Code Online (Sandbox Code Playgroud)
我像下面这样解决了它:
at_the_end(X, [], [X]).
at_the_end(X, [H|T], [H|T2]) :-
at_the_end(X, T, T2).
revert([], []).
revert([H|T], Out) :-
revert(T, Out1),
at_the_end(H, Out1, Out).
fib(0, 0).
fib(1, 1).
fib(N, F) :-
N > 1,
N1 is N - 1,
N2 is N - 2,
fib(N1, F1),
fib(N2, F2),
F is F1 + F2.
fibon(0, [0]).
fibon(N, [H|T]) :-
fib(N, H),
N1 is N - 1,
fibon(N1, T).
fibonacci(In, Out) :-
fibon(In, Out1),
revert(Out1, Out).
Run Code Online (Sandbox Code Playgroud)
您可以通过使递归谓词尾递归来提高速度:
fib_seq(0,[0]). % <- base case 1
fib_seq(1,[0,1]). % <- base case 2
fib_seq(N,Seq) :-
N > 1,
fib_seq_(N,SeqR,1,[1,0]), % <- actual relation (all other cases)
reverse(SeqR,Seq). % <- reverse/2 from library(lists)
fib_seq_(N,Seq,N,Seq).
fib_seq_(N,Seq,N0,[B,A|Fs]) :-
N > N0,
N1 is N0+1,
C is A+B,
fib_seq_(N,Seq,N1,[C,B,A|Fs]). % <- tail recursion
Run Code Online (Sandbox Code Playgroud)
首先让我们观察您的示例查询是否按预期工作:
?- fib_seq(6,L).
L = [0, 1, 1, 2, 3, 5, 8] ;
false.
Run Code Online (Sandbox Code Playgroud)
请注意,该列表没有 6 个元素,如您文章开头的示例所示,而是 7 个。这是因为谓词从零开始计数(顺便说一句,这与fibonacci/2您添加到帖子中的谓词的行为相同)。
出于比较(fib/2来自@Enigmativity 的帖子)原因,让我们reverse/2从以下位置移除目标fib_seq/2(然后您将获得除 N=0 和 N=1 以外的所有解决方案以相反的顺序):
?- time((fib(50000,L),false)).
% 150,001 inferences, 0.396 CPU in 0.396 seconds (100% CPU, 379199 Lips)
false.
?- time((fib_seq(50000,L),false)).
% 150,002 inferences, 0.078 CPU in 0.078 seconds (100% CPU, 1930675 Lips)
false.
Run Code Online (Sandbox Code Playgroud)
或者保持fib_seq/2原样并fib/2用一个额外的目标来衡量reverse/2(然后R在fib/2解决方案中对应L于fib_seq/2解决方案中):
?- time((fib(50000,L),reverse(L,R),false)).
% 200,004 inferences, 0.409 CPU in 0.409 seconds (100% CPU, 488961 Lips)
false.
?- time((fib_seq(50000,L),false)).
% 200,005 inferences, 0.088 CPU in 0.088 seconds (100% CPU, 2267872 Lips)
false.
Run Code Online (Sandbox Code Playgroud)
在旁注中,我会敦促您fibonacci/2在尝试获得更大的列表时将您的谓词与已发布的解决方案进行比较,例如 N > 30。