Результаты повторения хранятся в списке в прологе


Я пытаюсь создать Пролог-программу для решения рекуррентного уравнения:

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>

Что случилось, пожалуйста?

1 2

1 ответ:

Предикат 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 #> 0 и X2 #> 0 необходимы, потому что в противном случае вы получите ошибку out of local stack.