在Prolog中递归后返回一个值

时间:2010-01-29 16:44:17

标签: prolog logic

我决定研究一些逻辑编程,我偶然发现了一个问题。 它在SWI Prolog中编程。

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 个答案:

答案 0 :(得分:8)

A与规则正文中的任何内容均未统一。 prolog的工作方式是通过术语的统一。你不能像过程语言那样“返回”A.例如,当递归结束时,您希望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).

这是一个求和过程,它将对列表中的值和“返回N”求和,这是列表中值的总和。要调用此过程,您可以执行以下操作:

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

Prolog将回应:

  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.如果此调用成功,它最终会执行prolog将仅报告外部变量值。在内部_G417永远不会与其他任何东西统一。我认为问题在于理解Prolog的统一模型是如何运作的。

答案 1 :(得分:2)

我这里没有我的prolog编译器,但是你尝试过以下几点:

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).