Правильное использование предиката is / 2 в рекурсии Пролога - PullRequest
0 голосов
/ 24 августа 2018

Я новичок в Прологе с опытом программирования. Решая задания с этого сайта , я наткнулся на два упражнения: первое касается нахождения k-го элемента списка , второе - нахождения списка длина . Это классические задачи обработки списков с довольно простым решением, в том числе и для такого начинающего, как я. То, что я не смог понять, было (очевидно) другое использование встроенного предиката is/2. Насколько мне известно, этот предикат заставляет Пролога выполнять арифметическое вычисление и, возможно, присваивать результат левому члену. Мне сказали, что нужно знать, что, , хотя можно использовать переменные в правой части, они должны быть созданы с использованием термина без переменных в момент оценки .

Для первого упражнения предлагаемое решение следующее:

element_at(X,[X|_],1).
element_at(X,[_|L],K) :- K > 1, K1 is K - 1, element_at(X,L,K1).

и способ использования is имеет смысл для меня: поскольку K предоставляется в качестве аргумента, K1 может быть немедленно оценен и предоставлен как новый аргумент в рекурсивном вызове.

Путем написания Решением второго упражнения, а именно поиска длины списка, я придумал следующее:

my_length([], 0).
my_length([_|L], K) :- K is K1 + 1, my_length(L, K1).

и Prolog был уведомлен о том, что «аргументы недостаточно проработаны» .
Правильное решение оказалось таким:

my_length([], 0).
my_length([_|L], K) :- my_length(L, K1), K is K1 + 1.

В этом случае рекурсивный вызов выполняется перед , оценивая K с помощью is. В предыдущем упражнении это было сделано после оценки K is K-1.

Я думаю, что я неправильно понял некоторые ключевые понятия. В каких случаях is/2 должен использоваться до рекурсивного вызова и, с другой стороны, когда он должен использоваться после? Почему это так?
Любая помощь и объяснения приветствуются (я использую SWI-Prolog 7.6.4).

1 Ответ

0 голосов
/ 25 августа 2018

is следует использовать только тогда, когда все переменные в его правом члене уже созданы.Вы сами так говорите.Итак, в вашем предикате at он спроектирован так, что K должен быть уже создан для числового выражения при вызове предиката в запросе, т. Е. Любой другой запрос вызовет ошибку,Поскольку K уже создан, можно вызывать is.

Во втором предикате K - это выход , который вы ожидаете (а также, возможно, вход, который должен быть проверен).Поскольку не гарантированно будет известно при выполнении вызова, такой запрос должен быть разрешен для работы.Это означает, что K нельзя считать известным.И если он неизвестен, is не может быть вызван в это время, иначе это вызовет ошибку.

Таким образом, мы сначала выполняем рекурсивный вызов, поскольку он обязательно создаст экземпляр K, если это еще не было.

...