递归或

时间:2019-07-03 15:49:25

标签: prolog

我对prolog非常陌生,我想编写一个程序,该程序将数字增加或减少1,然后对结果进行相同的操作三次。我期望的结果是一系列三个数字,代表了所有可能的结果。例如,如果我给它编号4,我可以得到

567 565 545 543 456 454 434 432

更正 567 565 545 543 345 343 323 321

我认为对于某些组合或递归以及or条件而言,这是有意义的。

aos(_,3):- write('end').
aos(J,X):- (N is J+1, write(N),Y is X+1,aos(N,Y)); 
           (N is J-1, write(N), Y is X+1,aos(N,Y)).

上面是我的数据库文件,下面是我运行的查询。

aos(4,0).

我将得到的输出是

567end,然后当我单击下一步时,它将继续输出89101112...

我不明白为什么会这样,我将不胜感激。

1 个答案:

答案 0 :(得分:1)

问题在于,当您要求下一个解决方案时,X会增加到4。递归仍在继续,但是由于X现在大于3,您的终端大小写将永远不匹配。

您可以这样看到自己:

?- spy(aos/2).
% Spy point on aos/2
true.

[debug]  ?- aos(4,0).
 * Call: (8) aos(4, 0) ? Options:
+:                  spy        -:              no spy
/c|e|r|f|u|a goal:  find       .:              repeat find
a:                  abort      A:              alternatives
b:                  break      c (ret, space): creep
[depth] d:          depth      e:              exit
f:                  fail       [ndepth] g:     goals (backtrace)
h (?):              help       i:              ignore
l:                  leap       L:              listing
n:                  no debug   p:              print
r:                  retry      s:              skip
u:                  up         w:              write
m:                  exception details
C:                  toggle show context
 * Call: (8) aos(4, 0) ? creep
   Call: (9) _850 is 4+1 ? creep
   Exit: (9) 5 is 4+1 ? creep
   Call: (9) write(5) ? creep
5
   Exit: (9) write(5) ? creep
   Call: (9) _856 is 0+1 ? creep
   Exit: (9) 1 is 0+1 ? creep
 * Call: (9) aos(5, 1) ? creep
   Call: (10) _862 is 5+1 ? creep
   Exit: (10) 6 is 5+1 ? creep
   Call: (10) write(6) ? creep
6
   Exit: (10) write(6) ? creep
   Call: (10) _868 is 1+1 ? creep
   Exit: (10) 2 is 1+1 ? creep
 * Call: (10) aos(6, 2) ? creep
   Call: (11) _874 is 6+1 ? creep
   Exit: (11) 7 is 6+1 ? creep
   Call: (11) write(7) ? creep
7
   Exit: (11) write(7) ? creep
   Call: (11) _880 is 2+1 ? creep
   Exit: (11) 3 is 2+1 ? creep
 * Call: (11) aos(7, 3) ? creep
   Call: (12) write(end) ? creep
end
   Exit: (12) write(end) ? creep
 * Exit: (11) aos(7, 3) ? creep
 * Exit: (10) aos(6, 2) ? creep
 * Exit: (9) aos(5, 1) ? creep
 * Exit: (8) aos(4, 0) ? Unknown option (h for help)
 * Exit: (8) aos(4, 0) ? creep
true ;
 * Redo: (11) aos(7, 3) ? creep
   Call: (12) _886 is 7+1 ? creep
   Exit: (12) 8 is 7+1 ? creep
   Call: (12) write(8) ? creep
8
   Exit: (12) write(8) ? creep
   Call: (12) _892 is 3+1 ? creep
   Exit: (12) 4 is 3+1 ? creep
 * Call: (12) aos(8, 4) ? creep
   Call: (13) _898 is 8+1 ? creep
   Exit: (13) 9 is 8+1 ? creep
   Call: (13) write(9) ? creep
9

问题在于,当您寻求其他解决方案时,Prolog的最后选择点是aos(7,3)之后最里面的一个。因此它将进入J = 7和X = 3的第二个分支。您可以这样解决此问题:

aos(_,3):- write('end').
aos(J,X):- X < 3, ((N is J+1, write(N),Y is X+1,aos(N,Y)); 
                   (N is J-1, write(N), Y is X+1,aos(N,Y))).

但是,这不会产生您想要的输出序列。您将获得567 5 45 3 345 3 23 1.我不完全确定要获得该输出序列需要做什么,但是我怀疑您需要将三个加法项组合在一起,并使用第二个变量将它们分散开,这导致你麻烦我可能会这样实现:

inc_or_dec(X, Y) :- succ(X, Y).
inc_or_dec(X, Y) :- succ(Y, X).

aos(N) :- 
    inc_or_dec(N , N1), 
    inc_or_dec(N1, N2), 
    inc_or_dec(N2, N3), 
    write(N1), write(N2), write(N3), write('end'), nl.

这对于Prolog来说更明显,在这里真正的选择点不在,即不在三个一组的单个数字之间。但是,这仍然不能完全满足您所需的顺序。您将获得567 565 545 543 345 343 323321。如果最初要获得4的解,则必须放宽约束并使X保持不变,但是如果这样做,您还将获得444和555.了解您要达到的目标可能会有所帮助,而不只是了解您如何实现的。