База знаний
add(0,Y,Y). // clause 1
add(succ(X),Y,succ(Z)) :- add(X,Y,Z). // clause 2
Запрос
add(succ(succ(succ(0))), succ(succ(0)), R)
Трассировка
Call: (6) add(succ(succ(succ(0))), succ(succ(0)), R)
Call: (7) add(succ(succ(0)), succ(succ(0)), _G648)
Call: (8) add(succ(0), succ(succ(0)), _G650)
Call: (9) add(0, succ(succ(0)), _G652)
Exit: (9) add(0, succ(succ(0)), succ(succ(0)))
Exit: (8) add(succ(0), succ(succ(0)), succ(succ(succ(0))))
Exit: (7) add(succ(succ(0)), succ(succ(0)), succ(succ(succ(succ(0)))))
Exit: (6) add(succ(succ(succ(0))), succ(succ(0)), succ(succ(succ(succ(succ(0))))))
Мой вопрос
- Я вижу, как рекурсивный вызов в разделе 2 удаляет внешний succ () при каждом вызове аргумента 1.
- Я вижу, как он добавляет внешний succ () к аргументу 3 при каждом вызове.
- Я вижу, когда 1-й аргумент в результате этих рекурсивных вызовов достигает 0. В этот момент я вижу, как 1-е предложение копирует 2-й аргумент в 3-й аргумент.
Вот где я запутался.
После выполнения 1-го предложения автоматически выполняется и 2-е предложение, а затем добавляется succ () к первому аргументу?
Кроме того, как программа завершается и почему она просто не продолжает бесконечно добавлять succ () к первому и третьему аргументу?
Объяснение с сайта LearnPrologNow.com (которое я не понимаю)
Давайте шаг за шагом рассмотрим, как Prolog обрабатывает этот запрос. Ниже приведено дерево трассировки и поиска по запросу.
Первый аргумент не равен 0, что означает, что можно использовать только второе предложение для add / 3. Это приводит к рекурсивному вызову add / 3. Самый внешний функтор succ удаляется из первого аргумента исходного запроса, и результат становится первым аргументом рекурсивного запроса. Второй аргумент передается рекурсивному запросу без изменений, а третий аргумент рекурсивного запроса - это переменная, внутренняя переменная _G648 в трассировке, приведенной ниже. Обратите внимание, что _G648 еще не создан. Однако он разделяет значения с R (переменная, которую мы использовали в качестве третьего аргумента в исходном запросе), потому что R был создан как succ (_G648), когда запрос был объединен с заголовком второго предложения. Но это означает, что R больше не является полностью необоснованной переменной. Теперь это сложный термин, аргументом которого является (неустановленная) переменная.
Следующие два шага по сути такие же. С каждым шагом первый аргумент становится на один слой меньше; И трассировка, и дерево поиска, приведенные ниже, хорошо это демонстрируют. В то же время succ-функтор добавляется к R на каждом шаге, но всегда оставляет самую внутреннюю переменную неустановленной. После первого рекурсивного вызова R завершается успешно (_G648). После второго рекурсивного вызова _G648 создается с помощью succ (_G650), так что R является succ (succ (_G650). После третьего рекурсивного вызова _G650 создается с помощью succ (_G652), и поэтому R становится succ (succ (succ ( _G652))). В дереве поиска показано пошаговое создание экземпляра.
На этом этапе все succ-функторы удалены с первого аргумента, и мы можем применить базовое предложение. Третий аргумент приравнивается ко второму аргументу, поэтому «дыра» (неустановленная переменная) в комплексном члене R, наконец, заполнена, и мы прошли.