Prolog-生成fibonacci级数

Prolog-生成fibonacci级数,prolog,fibonacci,Prolog,Fibonacci,我想写一个谓词,为给定的N生成斐波那契级数 fibon(6, X) -> X = [0,1,1,2,3,5]. 我有一个谓词来生成斐波那契数列的第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. 我试着写fibon/2,但它不起作用: fibon(N, [H

我想写一个谓词,为给定的N生成斐波那契级数

fibon(6, X) -> X = [0,1,1,2,3,5].
我有一个谓词来生成斐波那契数列的第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.
我试着写fibon/2,但它不起作用:

fibon(N, [H|T]) :-
    fib(N, H),
    N1 is N - 1,
    fibon(N1, T).
我按如下方式解决了这个问题:

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).

如果您愿意颠倒序列的结果顺序,则此操作有效:

fib(0, [0]). fib(1, [1,0]). fib(N, [R,X,Y|Zs]) :- N > 1, N1 is N - 1, fib(N1, [X,Y|Zs]), R is X + Y.
通过使递归谓词尾部递归,可以稍微加快速度:

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
请注意,列表中没有六个元素,如您在文章开头的示例中所示,而是七个元素。这是因为谓词从零开始计数(顺便说一句,这与您添加到帖子中的谓词
fibonacci/2
的行为相同)

为了比较(使用@Enigmativity的帖子中的
fib/2
)原因,让我们从
fib_seq/2
中删除目标
reverse/2
(然后您将得到除N=0和N=1之外的所有解决方案,顺序相反):

或者让
fib_seq/2
保持原样,用另一个目标
reverse/2
测量
fib/2
(然后
fib/2
解决方案中的
R
对应于
fib_seq/2
解决方案中的
L
):


另一方面,我建议您在尝试获取更大的列表时,比如N>30,将谓词
fibonacci/2
与发布的解决方案进行比较

只是为了好玩而使用
scanl
。还有一些标准的DCG

:-use_module(library(clpfd)).

my_plus(X,Y,Z):-
    Z#>=0,
    Z#=<1000, % Max size optional
    Z#=X+Y.

list([])     --> [].
list([L|Ls]) --> [L], list(Ls).

concatenation([]) --> [].
concatenation([List|Lists]) -->
        list(List),
        concatenation(Lists).

fib(Len,List1):-
    X0=1,
    length(List1,Len),
    length(End,2),
    MiddleLen #= Len - 3,
    length(Middle,MiddleLen),
    phrase(concatenation([[X0],Middle,End]), List1),
    phrase(concatenation([[X0],Middle]), List2),
    phrase(concatenation([Middle,End]), List3),
    scanl(my_plus,List2,X0,List3).
:-使用_模块(库(clpfd))。
我的加(X,Y,Z):-
Z#>=0,
Z#=[]。
列表([L|Ls])-->[L],列表(Ls)。
连接([])-->[]。
连接([List | Lists])-->
名单(名单),,
连接(列表)。
fib(Len,列表1):-
X0=1,
长度(列表1,Len),
长度(末端,2),
MiddleLen#=Len-3,
长度(中间、中间),
短语(串联([[X0],中间,结尾]),列表1,
短语(串联([[X0],中间]),列表2,
短语(连接([Middle,End]),列表3,
scanl(myu plus,列表2,X0,列表3)。

如果要收集斐波那契数列的第一个
N
元素列表,可以使用以下规则。记住初始化前两个谓词

fib(0, [1]).
fib(1, [1, 1]).

fib(N, L) :-
    N > 1,
    N1 is N - 1,
    N2 is N - 2,
    fib(N1, F1),
    last(F1, L1),
    fib(N2, F2),
    last(F2, L2),
    L_new is L1 + L2,
    append(F1, [L_new], L). 

fibon/2递归的基本情况在哪里?如果
N=0
,会发生什么情况?或者如果
N<0
?事实上,现在它可以工作了。我将实现这个问题。在递归子句中确实应该有一个
N>0
条件,以避免由于
N
变为<0而出现非终止问题。另外,您的基本情况可能应该是
fibon(0,[])
,因为
0
不是斐波那契数。如果您没有斐波那契数(0),那么您应该有一个空列表,是吗?您的意思是
append(F1[L_new],L)。
F
fib
中没有定义。是的,我的错。我会改正的!谢谢你的评论
?- 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.
?- 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.
:-use_module(library(clpfd)).

my_plus(X,Y,Z):-
    Z#>=0,
    Z#=<1000, % Max size optional
    Z#=X+Y.

list([])     --> [].
list([L|Ls]) --> [L], list(Ls).

concatenation([]) --> [].
concatenation([List|Lists]) -->
        list(List),
        concatenation(Lists).

fib(Len,List1):-
    X0=1,
    length(List1,Len),
    length(End,2),
    MiddleLen #= Len - 3,
    length(Middle,MiddleLen),
    phrase(concatenation([[X0],Middle,End]), List1),
    phrase(concatenation([[X0],Middle]), List2),
    phrase(concatenation([Middle,End]), List3),
    scanl(my_plus,List2,X0,List3).
fib(0, [1]).
fib(1, [1, 1]).

fib(N, L) :-
    N > 1,
    N1 is N - 1,
    N2 is N - 2,
    fib(N1, F1),
    last(F1, L1),
    fib(N2, F2),
    last(F2, L2),
    L_new is L1 + L2,
    append(F1, [L_new], L).