Prolog 斐波那契数生成的问题

Prolog 斐波那契数生成的问题,prolog,fibonacci,Prolog,Fibonacci,下面是我的第n个fibonacci数查找谓词,它是ok的: f(0,0). f(1,1). f(N,R):-P is N-1,Q is N-2,f(P,T1),f(Q,T2),R is T1+T2. 我试图用以下谓词生成斐波那契数: fgen(0,0). fgen(1,1). fgen(A,B):-fgen(X,Y),A is X+1,f(A,T),B is T. 当我使用fgen(X,Y)进行查询时。 它表明: ?- fgen(X,Y). X = 0 Y = 0 ; X = 1 Y =

下面是我的第n个fibonacci数查找谓词,它是ok的:

f(0,0).
f(1,1).
f(N,R):-P is N-1,Q is N-2,f(P,T1),f(Q,T2),R is T1+T2.
我试图用以下谓词生成斐波那契数:

fgen(0,0).
fgen(1,1).
fgen(A,B):-fgen(X,Y),A is X+1,f(A,T),B is T.
当我使用
fgen(X,Y)进行查询时。

它表明:

?- fgen(X,Y).

X = 0
Y = 0 ;

X = 1
Y = 1 ;

X = 1
Y = 1 ;
ERROR: Out of local stack
我使用了trace命令,结果如下:

?- trace,fgen(X,Y).
   Call: (9) fgen(_G281, _G282) ? creep
   Exit: (9) fgen(0, 0) ? creep

X = 0
Y = 0 ;
   Redo: (9) fgen(_G281, _G282) ? creep
   Exit: (9) fgen(1, 1) ? creep

X = 1
Y = 1 ;
   Redo: (9) fgen(_G281, _G282) ? creep
   Call: (10) fgen(_L178, _L189) ? creep
   Exit: (10) fgen(0, 0) ? creep
^  Call: (10) _G281 is 0+1 ? creep
^  Exit: (10) 1 is 0+1 ? creep
   Call: (10) f(1, _L179) ? creep
   Exit: (10) f(1, 1) ? creep
^  Call: (10) _G282 is 1 ? creep
^  Exit: (10) 1 is 1 ? creep
   Exit: (9) fgen(1, 1) ? creep

X = 1
Y = 1 ;
   Redo: (10) f(1, _L179) ? creep
^  Call: (11) _L207 is 1-1 ? creep
^  Exit: (11) 0 is 1-1 ? creep
^  Call: (11) _L208 is 1-2 ? creep
^  Exit: (11) -1 is 1-2 ? creep
   Call: (11) f(0, _L209) ? creep
   Exit: (11) f(0, 0) ? abort
% Execution Aborted
我正试图找到错误,但失败了。如何解决问题?

首先

fgen(A,B) :- fgen(X, Y), A is X+1, f(A, T), B is T.

fgen(A,B) :- fgen(X, _), A is X+1, f(A, B).
所以你有两个问题。一个是你正在生成然后扔掉Y,而singleton警告应该提醒你这一点。应始终通过将变量替换为\来响应单例警告;如果它看起来像是把你的代码变成了废话,那么你的代码就是废话。:)

另一个问题是
B is T
是不必要的(在这里使用
is/2
而不是
=/2
不会给您带来任何好处,因为右侧没有算术)

让我们试试这个:

fgen(A, B) :- fgen(X, A), B is X + A.
这几乎奏效了:

?- fgen(X, Y).
X = Y, Y = 0 ;
X = Y, Y = 1 ;
X = Y, Y = 0 ;
X = 1,
Y = 2 ;
X = Y, Y = 0 ;
X = 2,
Y = 3 ;
X = Y, Y = 0 ;
X = 3,
Y = 5 ;
X = Y, Y = 0 ;
X = 5,
Y = 8 ;
X = Y, Y = 0 ;
X = 8,
Y = 13 ;
X = Y, Y = 0 ;
X = 13,
Y = 21 .
所有这些无意义的零应该告诉你,你根本不需要你的第一个基本情况。毕竟,加零不会改变任何事情。如果删除该基本情况,将获得所需的行为:

?- fgen(X, Y).
X = Y, Y = 1 ;
X = 1,
Y = 2 ;
X = 2,
Y = 3 ;
X = 3,
Y = 5 ;
X = 5,
Y = 8 ;
X = 8,
Y = 13 ;
X = 13,
Y = 21

首先,您的
f/2
正常:

6 ?- f(10,X).

X = 55 ;
ERROR: (user://2:68):
        Out of local stack
您的条款应该是相互排斥的:

f(0,0).
f(1,1).
f(N,R):-N>1,
        P is N-1,Q is N-2,f(P,T1),f(Q,T2),R is T1+T2.
在没有
N>1
测试的情况下,重新启动时,最深目标
f(0,T2)
将与第三条规则重新匹配,单向进入负数,而不会返回。现在,对于互斥子句,这种不匹配被阻止,谓词变得确定性:

8 ?- f(10,X).

X = 55 ;

No
可能您试图生成所有可能的值,但出现错误:

9 ?- f(A,B).

A = 0,    B = 0 ;    
A = 1,    B = 1 ;
ERROR: (user://5:147):
        Arguments are not sufficiently instantiated
^  Exception: (8) _G230>1 ? abort
% Execution Aborted
因为第一个参数必须是一个完全实例化的数字,要与
一起使用,

因此,您的第二个谓词,
fgen(A,B)
。这有点不清楚,但从调用
f(a,T)
判断,它打算将
a
作为一个索引,
B
作为其相应的斐波那契数,一个接一个地生成答案序列
(0,0)、(1,1)、(2,1)、(3,2)、(4,3)、(5,5)、(6,8),…
。要枚举索引,我们可以定义

% natural(0).
% natural(A):- natural(B), A is B+1.

natural(N):- znat(0,N).
znat(N,N).
znat(A,N):- B is A+1, znat(B,N).
然后简单地

fgen(A,B):- natural(A), f(A,B).
现在,

natural/1的第一个(注释掉的)版本创建了一个线性长度的执行堆栈。第二个版本在恒定的堆栈空间中运行

当然,您的
f/2
是双重递归的,因此它将比
natural
更早地耗尽堆栈

12 ?- fgen(A,B).

A = 0,    B = 0 ;    
A = 1,    B = 1 ;    
A = 2,    B = 1 ;    
A = 3,    B = 2 ;    
A = 4,    B = 3 ;    
A = 5,    B = 5 ;    
A = 6,    B = 8