2

我正在尝试创建一个 Prolog 程序来解决循环方程:

f(1)=2, f(2)=5, f(n)=f(n-1)+2*f(n-2)

我使用下面的rec函数进行了管理,但是当我想将结果存储在列表中时(通过函数recList)我遇到了麻烦。
这是我的实现:

rec(1,2).
rec(2,5).
rec(X,N) :- X1 is X-1, X2 is X-2, rec(X1,N1), rec(X2,N2), N is N1+2*N2.

recList(0,[]).
recList(X,[N|L]) :- rec(X,N), X1 is X-1, recList(X1,L).

我的 recList 实现适用于通过第一个值调用它

?- recList(4,X). 

->

X = [19, 9, 5, 2] .

但如果它比两个元素长,当我用第二个调用它时它不会:

?- rekurList(X,[2]).
X = 1 .

?- rekurList(X,[5,2]).
X = 2 .

?- rekurList(X,[9,5,2]).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR:    [9] rec(_12587334,9)
ERROR:    [8] rekurList(_12587360,[9,5|...]) at /locaiton/rec.pl:6
ERROR:    [7] <user>

请问有什么问题吗?

4

1 回答 1

3

谓词is/2失败,因为is/2将右手结构计算为算术表达式。如果它不是有效的算术表达式或数字,则is/2失败。所以当你打电话

recList(X, [19, 9, 5, 2]).

你明白了rec/2: Arguments are not sufficiently instantiated。如果您运行跟踪器(在 SWISH 中,它是在线 SWI:trace, recList(X, [19, 9, 5, 2]).在 ECLiPSe 中您可以使用tkeclipse Tools->Tracer),您会得到如下信息:

Call:recList(_13806, [19, 9, 5, 2])
 Call:rec(_13806, 19)
 Call:_14048 is _13806+-1
 Exception:_14102 is _13806+-1
is/2: Arguments are not sufficiently instantiated

要解决此问题,您可以以这种方式使用库clpfd(我使用 SWI 编写了解决方案):

:- use_module(library(clpfd)).

rec(1,2).
rec(2,5).
rec(X,N):- 
    X1 #> 0,
    X1 #= X-1, 
    rec(X1,N1),
    X2 #> 0,
    X2 #= X-2,  
    rec(X2,N2),
    N #= N1+2*N2, !. %notice the cut (!)

recList(0,[]):-!.
recList(X,[N|L]):- 
    rec(X,N), 
    X1 #= X-1, 
    recList(X1,L).

询问:

?- recList(X, [19, 9, 5, 2]).
X = 4.
false.

?- recList(4,L).
L = [19, 9, 5, 2]
false

请注意,!需要进行剪切,否则在第一个解决方案之后,如果单击更多,则计算将永远不会结束。也需要X1 #> 0and X2 #> 0,否则会out of local stack出错。

于 2018-01-02T16:18:59.797 回答