проблема с генерацией числа Фибоначчи

Ниже приведен мой предикат для поиска 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,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

Я пытаюсь найти ошибку, но безуспешно. Как решить проблему?


person Md. Arafat Al Mahmud    schedule 08.03.2013    source источник


Ответы (2)


Для начинающих,

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
person Daniel Lyons    schedule 08.03.2013

Во-первых, ваш 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 его соответствующим числом Фибоначчи, генерирующим один за другим последовательность ответов (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 является дважды рекурсивным, поэтому он исчерпает стек намного раньше, чем natural когда-либо мог.

person Will Ness    schedule 09.03.2013