Возвращение значения после рекурсии в Прологе - PullRequest
3 голосов
/ 29 января 2010

Я решил изучить логику программирования и наткнулся на проблему. Это запрограммировано в SWI Пролог.

test(A, B, N):-
 nonvar(B),
 B = final,
 true.

test(A, B, N):-
 N > 2,
 test(A, final, N).

test(A, B, N):-
 N1 is N + 1,
 test(N1, B, N1).

Это всего лишь образец, который бесполезен, но сводит меня с ума.

Проблема в том, что когда код достигает значения true, он начинает отслеживание и отвечает "true" Но мне нужно «вернуть» значение A. Как мне это сделать?

Ответы [ 2 ]

8 голосов
/ 29 января 2010

А не объединяется с чем-либо в теле ваших правил. Пролог работает через унификацию терминов. Вы не можете «вернуть» А как процедурные языки как таковые. Например, что вы хотите, чтобы значение A было, когда рекурсия заканчивается? Я понятия не имею, что делает ваш код, поэтому позвольте мне использовать мой собственный пример.

  accumulate([], A, A).
  accumulate([H|T], A, N) :- A1 is A + H, accumulate(T, A1, N).

  sum([], 0).
  sum(L, N) :- accumulate(L,0,N).

Вот процедура суммирования, которая будет суммировать значения в списке и «return N», сумму значений в списке. Для вызова этой процедуры вы можете сделать это:

  sum([2, 3, 4], N).

И Пролог ответит:

  N = 9

Обратите внимание, что процедура накопления использует A в качестве аккумулятора, когда продолжается рекурсия. Таким образом, A сохраняет промежуточную сумму, а N - окончательный ответ, который она возвращает. Во время рекурсии N не унифицируется ни с какой реальной ценностью.

На последнем этапе рекурсии, то есть, когда список пуст, значение A объединяется с N, фактически возвращая N.


Давайте сделаем След.

 [trace] 4 ?- test(A, B, 0).
   Call: (7) test(_G417, _G418, 0) ? creep//A unifies with _G417 (internal variable name), B with _G418 and N with 0.
   Call: (8) nonvar(_G418) ? creep
   Fail: (8) nonvar(_G418) ? creep
   Redo: (7) test(_G417, _G418, 0) ? creep//Unifies with clause 2, 
^  Call: (8) 0>2 ? creep
^  Fail: (8) 0>2 ? creep
   Redo: (7) test(_G417, _G418, 0) ? creep //Unifies with clause 3
^  Call: (8) _L183 is 0+1 ? creep
^  Exit: (8) 1 is 0+1 ? creep
   Call: (8) test(1, _G418, 1) ? creep //recursive call, unifies with 
   Call: (9) nonvar(_G418) ? creep
   Fail: (9) nonvar(_G418) ? creep
   Redo: (8) test(1, _G418, 1) ? creep
^  Call: (9) 1>2 ? creep
^  Fail: (9) 1>2 ? creep
   Redo: (8) test(1, _G418, 1) ? creep
^  Call: (9) _L195 is 1+1 ? creep
^  Exit: (9) 2 is 1+1 ? creep
   Call: (9) test(2, _G418, 2) ? creep
   Call: (10) nonvar(_G418) ? creep
   Fail: (10) nonvar(_G418) ? creep
   Redo: (9) test(2, _G418, 2) ? creep
^  Call: (10) 2>2 ? creep
^  Fail: (10) 2>2 ? creep
   Redo: (9) test(2, _G418, 2) ? creep
^  Call: (10) _L207 is 2+1 ? creep
^  Exit: (10) 3 is 2+1 ? creep
   Call: (10) test(3, _G418, 3) ? creep
   Call: (11) nonvar(_G418) ? creep
   Fail: (11) nonvar(_G418) ? creep
   Redo: (10) test(3, _G418, 3) ? creep
^  Call: (11) 3>2 ? creep
^  Exit: (11) 3>2 ? creep
   Call: (11) test(3, final, 3) ? creep
   Call: (12) nonvar(final) ? creep
   Exit: (12) nonvar(final) ? creep
   Call: (12) final=final ? creep
   Exit: (12) final=final ? creep
   Call: (12) true ? creep
   Exit: (12) true ? creep
   Exit: (11) test(3, final, 3) ? creep
   Exit: (10) test(3, _G418, 3) ? creep
   Exit: (9) test(2, _G418, 2) ? creep
   Exit: (8) test(1, _G418, 1) ? creep
   Exit: (7) test(_G417, _G418, 0) ? creep

Теперь обратите внимание на точку на трассе, где я отметил //A unifies with _G417 (internal variable name), B with _G418 and N with 0.. В этот момент A - ваша внешняя переменная, а _G417 - ваша внутренняя A. Если этот вызов завершится успешно, то в конечном итоге пролог сообщит только о значениях внешней переменной. Внутренне _G417 никогда не объединяется ни с чем другим. Я думаю, что проблема заключается в понимании того, как работает модель объединения Пролога.

2 голосов
/ 29 января 2010

У меня нет моего пролога, но вы пробовали что-то вроде:

test(A, B, N, A):-
 nonvar(B),
 B = final,
 true.

test(A, B, N, Result):-
 N > 2,
 test(A, final, N, Result).

test(A, B, N, Result):-
 N1 is N + 1,
 test(N1, B, N1, Result).
...