下面是我的第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
我试图找到错误,但失败了。如何解决这个问题?
答案 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
更早地耗尽堆栈。