Prolog上的递归谓词问题

时间:2018-12-09 18:06:59

标签: prolog

目标a(3, X)应该返回6。基于此代码。我已经将其转换为Prolog代码,但是在递归谓词中存在问题。前两行用于0和1返回相同的值。

c=1
  for i = 2 to n do
    if c > i then
      c=c-1
    else
      c=c+1
    end if
end for
return c

但是在第4步,它得到结果,然后返回到第2步,并通过迭代返回错误的结果。我认为这是一个统一的问题,但找不到哪里。

a(N, N) :- N < 2, !.
a(N, X) :- a(1, 2, N, X).

第2步。

a(C1, I, N, C1) :- I > N, !.

第3步。

a(C, I, N, C1) :- C > I, !,
                 C1 is C - I,
                 I1 is I + 1,
                 a(C1, I1, N, C1).

第4步。

a(C, I, N, C1) :- C =< I, !,
                 C1 is C + I,
                 I1 is I + 1,
                 a(C1, I1, N, C1).

这是跟踪。

[trace]  ?- a(3, X).
   Call: (8) a(3, _1238) ? creep
   Call: (9) 3<2 ? creep
   Fail: (9) 3<2 ? creep
   Redo: (8) a(3, _1238) ? creep
   Call: (9) a(1, 2, 3, _1238) ? creep
   Call: (10) 2>3 ? creep
   Fail: (10) 2>3 ? creep
   Redo: (9) a(1, 2, 3, _1238) ? creep
   Call: (10) 1>2 ? creep
   Fail: (10) 1>2 ? creep
   Redo: (9) a(1, 2, 3, _1238) ? creep
   Call: (10) 1=<2 ? creep
   Exit: (10) 1=<2 ? creep
   Call: (10) _1474 is 1+2 ? creep
   Exit: (10) 3 is 1+2 ? creep
   Call: (10) _1480 is 2+1 ? creep
   Exit: (10) 3 is 2+1 ? creep
   Call: (10) a(3, 3, 3, 3) ? creep
   Call: (11) 3>3 ? creep
   Fail: (11) 3>3 ? creep
   Redo: (10) a(3, 3, 3, 3) ? creep
   Call: (11) 3>3 ? creep
   Fail: (11) 3>3 ? creep
   Redo: (10) a(3, 3, 3, 3) ? creep
   Call: (11) 3=<3 ? creep
   Exit: (11) 3=<3 ? creep
   Call: (11) _1486 is 3+3 ? creep
   Exit: (11) 6 is 3+3 ? creep
   Call: (11) _1492 is 3+1 ? creep
   Exit: (11) 4 is 3+1 ? creep
   Call: (11) a(6, 4, 3, 6) ? creep
   Call: (12) 4>3 ? creep
   Exit: (12) 4>3 ? creep
   Exit: (11) a(6, 4, 3, 6) ? creep  !!! SHOULD STOP HERE !!!
   Exit: (10) a(3, 3, 3, 3) ? creep
   Exit: (9) a(1, 2, 3, 1) ? creep
   Exit: (8) a(3, 1) ? creep
X = 1 .

1 个答案:

答案 0 :(得分:0)

您需要另一个变量。您正在“超载” math.sqrt,因此在进行递归调用时它已被实例化(绑定),并且最终在跟踪中出现了类似的事情(请注意,使用显示的代码,我不会得到与您所做的相同的跟踪,因此您对代码做了一些不同的操作):

C1

所以这是一个带有附加变量的更正:

| ?- a(3,X).
      1    1  Call: a(3,_23) ?
      2    2  Call: 3<2 ?
      2    2  Fail: 3<2 ?
      2    2  Call: a(1,2,3,_23) ?
      3    3  Call: 2>3 ?
      3    3  Fail: 2>3 ?
      3    3  Call: 1>2 ?
      3    3  Fail: 1>2 ?
      3    3  Call: 1=<2 ?
      3    3  Exit: 1=<2 ?
      4    3  Call: _23 is 1+2 ?
      4    3  Exit: 3 is 1+2 ?
      5    3  Call: _174 is 2+1 ?
      5    3  Exit: 3 is 2+1 ?
      6    3  Call: a(3,3,3,3) ?
      7    4  Call: 3>3 ?
      7    4  Fail: 3>3 ?
      7    4  Call: 3>3 ?
      7    4  Fail: 3>3 ?
      7    4  Call: 3=<3 ?
      7    4  Exit: 3=<3 ?
      8    4  Call: 3 is 3+3 ?
      8    4  Fail: 3 is 3+3 ?  <--- FAILS HERE: DUE TO C1 ALREADY BOUND
                                     3 cannot be 3+3 !
      6    3  Fail: a(3,3,3,3) ?
      2    2  Fail: a(1,2,3,_23) ?
      1    1  Fail: a(3,_23) ?

(1 ms) no

然后您得到:

a(C, I, N, C1) :- C > I, !,
                 C2 is C - I,
                 I1 is I + 1,
                 a(C2, I1, N, C1).

a(C, I, N, C1) :- C =< I, !,
                 C2 is C + I,
                 I1 is I + 1,
                 a(C2, I1, N, C1).

顺便说一句,不要那么快就在整个代码中散布剪切。如果没有他们,请首先使一切正常。然后将它们非常有意地修剪决策分支。它们有时会修剪出您真正想要的路径,并导致不良结果。