#list #recursion #prolog #logic
#Список #рекурсия #пролог #Логические
Вопрос:
Я только начал работать в прологе, и у меня есть вопрос, касающийся рекурсии.
Я в основном хочу подсчитать, сколько раз определенное значение находится в списке, поэтому, например, у меня есть:
count( a, [ a, s, d, f, g, a, s, d, a, s ], W ). W = 3.
Где я хочу подсчитать количество раз, когда «а» находится в списке, и сохранить число в «W».
Правильный ответ таков
count( _, [], 0 ). count( A, [B|S], X ) :- A==B, count( A, S, Y ), X is Y 1. count( A, [B|S], X ) :- A == B, count( A, S, X ).
Однако я не понимаю, почему в строке 2 в конце стоит «X равно Y 1». Разве линия не должна быть скорее
count( A, [A|S], X ) :- Y is X 1, count( A, S, Y ).
В этом случае мы сначала устанавливаем Y равным 1, затем снова отправляем его на «подсчет» с рекурсией.
Если кто-нибудь может мне помочь, я был бы вам очень признателен!
Ответ №1:
Учтите это, когда будете звонить:
?- count(a,[a,s,d,f,g,a,s,d,a,s],W).
…тогда первый предикат, который соответствует, является count(A,[B|S],X)
. Таким образом, это означает, что он видит это так, как count(a,[a|S],X)
если S
бы amp; X
были переменными. X
это только W
из исходного вызова, так что это все еще переменная.
Предположение, что Y is X 1
это затем оценивается, не имеет смысла, как X
и переменная.
Исходный предикат, однако, имеет смысл.
count(A,[B|S],X) :- A==B, count(A,S,Y), X is Y 1.
Когда он рекурсирует, он отправляет новую переменную Y
во 2-й count/3
предикат (или просто передает ту же переменную в 3-м предикате). И он продолжает делать это до тех пор, пока не достигнет базового случая, когда он, наконец, объединит переменную в 0
. В этот момент он разматывает рекурсию, и теперь он, наконец, может это сделать X is Y 1
(потому Y
что это значение) и, следовательно X
, теперь является значением.
Пролог-забавный язык, потому что в нем почти есть ощущение путешествия во времени, когда вам нужно думать вперед и назад, чтобы понять, как работает программа.
Комментарии:
1. о, ух ты, теперь я понимаю! Большое спасибо!
Ответ №2:
count( A, [B|S], X ) :- A==B, count( A, S, Y ), X is Y 1.
Это означает: Если S
содержит Y
вхождения A
, и A == B
, то [B | S]
содержит еще одно вхождение A
.
Например, представьте, что мы добираемся сюда, подсчитывая вхождения prolog
[prolog, prolog, prolog]
. [B | S] = [prolog, prolog, prolog]
, итак S = [prolog, prolog]
. Количество вхождений prolog
in S
равно 2, так что мы должны были бы Y = 2
. Количество вхождений prolog
in [B | S]
равно 3, так что у нас должно быть X = 3
. Как только мы узнаем Y = 2
, то X is Y 1
вычисляем это правильное значение X
.
count( A, [A|S], X ) :- Y is X 1, count( A, S, Y ).
Это означало бы: если [A | S]
содержит X
вхождения A
, то S
содержит еще одно вхождение A
. Этого не может быть.
Снова используя приведенный выше пример: Явно [A | S] = [prolog, prolog, prolog]
содержит 3 вхождения prolog
, поэтому X = 3
должно сохраняться. Но тогда Y
должно было бы быть 4, и цель в теле попыталась бы доказать, что S = [prolog, prolog]
содержит 4 вхождения prolog
. Этого явно не может быть.
Обратите внимание, что это объяснение просто касается значения предиката. Это не требует от нас думать о рекурсии, или о порядке целей, или о точном способе выполнения программы на самом деле. При программировании на прологе сначала постарайтесь четко понять логический смысл ваших программ.