科隆纳西数生成的麻烦

时间:2013-03-08 17:28:50

标签: prolog fibonacci

下面是我的第N个斐波那契数字发现谓词,这是好的:

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

我试图找到错误,但失败了。如何解决这个问题?

2 个答案:

答案 0 :(得分:0)

首先,

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,单身警告应该提醒你这个。应始终通过用_替换变量来响应单例警告;如果它看起来像你的代码变成废话,你的代码是无稽之谈。 :)

另一个问题是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

答案 1 :(得分:0)

首先,您的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

因为第一个参数必须是完全实例化的数字,才能与>is一起使用。

因此你的第二个谓词fgen(A,B)。这有点不清楚,但通过调用f(A,T)来判断它A是一个索引,B是否对应斐波那契数,逐个生成答案序列{{ 1}}。要枚举索引,我们可以定义

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

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 的第一个(注释掉的)版本创建了一个线性长度执行堆栈。第二个版本在固定堆栈空间中运行。

当然,你的natural/1是双递归的,所以它会比f/2更早地耗尽堆栈。