Рекурсия с или случаи - PullRequest
1 голос
/ 03 июля 2019

Я очень новичок в прологе, и я хотел написать программу, которая будет увеличивать или уменьшать число на 1, а затем делать то же самое с результатом в три раза. Результатом, который я ожидал, была серия из трех чисел, представляющих все возможные варианты. Например, если я дам ему число 4, я могу получить,

567 565 545 543 456 454 434 432

коррекция 567 565 545 543 345 343 323 321

Я думал, что это будет иметь смысл для некоторой комбинации или рекурсии и условия или.

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 Ответ

1 голос
/ 03 июля 2019

Проблема в том, что когда вы запрашиваете следующее решение, 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

Проблема в том, что когда вы просите другое решение, последняя точка выбора Пролога была самой внутренней после 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.

Это делает более очевидным для Пролога, где реальные точки выбора находятся, то есть не между отдельными цифрами в группах по три. Однако, это все еще не совсем дает вам последовательность, которую вы хотите; вы получите 567 565 545 543 345 343 323 321. Если вы хотите получить решения с 4 изначально, вам придется ослабить ограничение и позволить X появиться без изменений, но если вы сделаете это, вы также получите последовательности, такие как 444 и 555. Может быть полезно знать, чего вы пытаетесь достичь, а не просто как вы пытаетесь этого достичь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...