
- •Глава 11 Отсечения и отрицание
- •11.1. Зеленые отсечения: выражение детерминизма
- •11.2. Оптимизация остатка рекурсии
- •11.3. Отрицание
- •11.4. Красные отсечения: устранение явных условий
- •11.5. Правила по умолчанию
- •1) «На бобах» остались Макдаф и, что уж совсем обидно, Макдональд. - прим.Ред.
- •11.6. Дополнительные сведения
- •Глава 12 Внелогические предикаты
- •12.1. Ввод-вывод
- •12.2. Доступ к программам и обработка программ
- •12.3. Запоминающие функции
- •12.4. Интерактивные программы
- •12.5. Циклы, управляемые отказом
- •12.6. Дополнительные сведения
11.3. Отрицание
Использование зеленого отсечения не влияет на декларативное значение программ на Прологе. Однако с учетом процедурного поведения отсечение может быть в ограниченной мере использовано для выражения безрезультатной информации.
Отсечение является основой реализации в Прологе ограниченной формы отрицания, называемой отрицание как безуспешное выполнение. Программа 11-о задает стандартное определение отношения not (Goal), которое истинно, если цель Goal не выполнена. Она основана на использовании метапеременной и системного предиката fail, который никогда не выполняется (т.е. отсутствуют определяющие его предложения). Конъюнкция отсечения и предиката fail представляет комбинацию “omceченue-fail”. Мы употребляем not как префиксный оператор.
notX
Х недоказуемо.
not XX, X,!. fail.
not X
Программа 11.6. Отрицание как безуспешное выполнение.
Рассмотрим, как работает программа 11.6 при поиске ответа на вопрос not G? Применяется первое правило, и использование метапеременной задает обращение к цели G. Если цель G выполнена, то мы сталкиваемся с отсечением. В вычислении фиксируется выбор первого правила, и цель not не выполнена. "Если цель G не выполнена, то применяется второе правило программы 11.6, приводящее к успешному вычислению. Следовательно, цель notG не выполнена, если выполнена цель G, и наоборот.
Для того чтобы программа 11.6 функционировала должным образом, требуется именно такой порядок правил. Здесь мы сталкиваемся с новой, не всегда желательной ситуацией в программировании на Прологе. До сих пор порядок правил влиял только на порядок появления решений. Теперь порядок правил может изменить значение программы. Процедуры, в которых порядок правил является критическим в этом смысле, следует рассматривать как единый объект, а не как набор отдельных предложений.
Остановка вычислений цели not G зависит от остановки вычислений цели G. Если вычисления цели G остановятся, то остановятся и вычисления цели notG. Если вычисления цели G не остановятся, то вычисления цели notG могут остановиться или не остановиться в зависимости от того, будет ли в дереве поиска найдена успешная вершина, прежде чем вычисление пойдет по бесконечной ветви. Рассмотрим незавершающуюся программу:
женаты (авраам, сара).
женаты (X,Y) женаты (Y,X).
Решение вопроса not женаты (авраам, сара)?. приведет к остановке (безуспешного) вычисления, хотя решение вопроса женаты (авраам. сара)? не останавливается.
Значение отношения
not,
определяемого в программе
11.6, отличается
от строгого логического отрицания.
Нельзя также сказать, что программа
реализует полное и точное определение
отрицания как безуспешного выполнения
в смысле теории гл.
5.
Неполнота такой реализации проистекает от неполноты реализации в Прологе вычислительной модели логического программирования. В логическом программировании отрицание как безуспешное выполнение определяется в терминах дерева конечного безуспешного поиска. Вычисления в Прологе не гарантируют нахождение такого дерева, даже если оно существует. Имеются цели, которые могут быть не выполнены при подобном отрицании, однако решение этих целей в соответствии с правилом вычислений в Прологе не останавливается. Например, решение вопроса not(p(X),q(X))? приводит к незавершающейся работе программы
В
действительности Пролог-10 использует
предикат \
+, а не
not,
но это не должно вводить в заблуждение.
Прим. перев.
p(s(X))р(Х).
q(a).
Вопрос можно решить, если выбрать сначала цель q(X), так как этот выбор приводит к дереву конечного безуспешного поиска.
Неадекватность программы 11.6 связана также с порядком обхода дерева поиска, что проявляется в случае использования отношения not в конъюнкции с другими целями. Рассмотрим использование отношения not в определении предиката не-женатый_студент (X) для кого-то, кто и студент, и не женат. Определение приведено в программе 5.1:
неженатый студент (X) not женат (X), студент (X).
студент (билл.)
женат(джо).
Решение вопроса неженатый_студент (X)?. с использованием приведенных сведений безуспешно, несмотря на то что решение Х = билл логически следует из правила и двух фактов. Это связано с тем, что цель not женат (X) не выполнена из-за решения X = джо. В данном случае проблема может быть устранена перестановкой целей в теле правила.
Аналогичным примером является вопрос not(X = l),X = 2?, который, несмотря на то что он верен, приводит к безуспешному вычислению.
Как показывают приведенные выше примеры, реализация отрицания как безуспешного выполнения с помощью комбинации “отсечение-fail” приводит к некорректной работе для неосновных целей. В большинстве стандартных реализации языка Пролог ответственность за то, что под отрицанием находятся основные цели, ложится на программиста. Проверка может выполняться или при статическом анализе программы, или в процессе вычислений с помощью предиката ground, описанного в программе 10,4.
Предикат not очень полезен. С его помощью можно вводить интересные понятия. Рассмотрим, например, предикат disjoint (Xs.Ys), выполненный, если списки Xs и Ys не имеют общих элементов. Этот предикат можно задать следующим образом:
disjoint(Xs,Ys) not(member(Z, Xs),member(Z, Ys)).
В программах, приведенных в книге, встретятся и другие примеры применения предиката not.
Комбинация “отсечение-fail”, использованная в программе 11.6, имеет и более общее применение. Она позволяет прервать вычисление на ранней стадии. В предложении, содержащем “отсечение-fail”, утверждается, что поиск не должен быть (и не будет) продолжен.
Некоторые отсечения в комбинации “отсечение-fail” являются зелеными отсечениями. Это означает, что значение программы не изменится, если удалить предложение, содержащее данную комбинацию. Рассмотрим в качестве примера программу 10.4, определяющую предикат ground. Можно добавить правило, сокращающее поиск и не влияющее на значение программы:
ground (Term) var(Term),!, fail.
Использование отсечения в программе 11.6, задающей предикат not, является красным, а не зеленым. Работа программы после удаления отсечения будет отличаться от требуемой.
Комбинац1ия “отсечение-fail” применяется и при реализации других системных предикатов, использующих отрицание. Например, программа 11.7 дает простую реализацию предиката с помощью унификации и комбинации “отсечений-fail”, а не с помощью бесконечной таблицы. Данная программа также работает правильно лишь для основных целей.
X Y-
X и У неунифицируемы.
Х Х !, fail. Х Y.
Программа 11.7. Реализация отношения
Изобретательность, хорошее понимание алгоритма унификации и процесса вычисления в Прологе позволяют строить интересные определения многих металогических предикатов. Уровень требуемых ухищрений можно оценить, рассмотрев программу, определяющую предикат same_var (X, Y). Этот предикат выполнен в том случае, если Х и Y- одна .и та же переменная, в противном случае он ложен.
Same_var(foo,Y)var(Y),!,fai. Same_var(X,Y)var(X),var(Y).
Довод в пользу правильности определения: “Если аргументы предиката Same_vаг -одна и та же переменная, то сопоставление значения foo аргументу Х приведет к такому же сопоставлению и для второго аргумента, так что первое правило будет неприменимо. Применение второго правила приведет к успешному решению. Если какой-либо из аргументов не является переменной, то оба правила неприменимы. Если аргументы - различные переменные, то первое правило приведет к безуспешному вычислению, а отсечение воспрепятствует рассмотрению второго правила” (O'Keef, 1983).
Упражнения к разд. 113
1. Определите предикат \ = =, используя предикат == = и конструкцию отсечение-fail”.
2. Определите предикат nonvar, используя предикат var и конструкцию “отсечение - fail”.