Отрицание как неудача. Предикат not
Рассмотрим фразу: «Ваня любит все игры кроме баскетбола.». Попробуем записать её на Прологе. Первая часть этого утверждения выражается легко: «Ваня любит Х, если Х – игра», или же:
like(wanja,X):-game(X).
Однако необходимо исключить баскетбол. Это можно сделать, воспользовавшись иной формулировкой:
Если Х – баскетбол, тогда „Ваня любит Х” не будет истиной, иначе, если Х – игра, то „Ваня любит Х”.
Для реализации этого на Прологе воспользуемся предикатом fail, который всегда завершается неуспешно и при этом влечёт неуспешное завершение и той фразы, являющейся для него родительской.
like(wanja, X):- basketball(X),!,fail.
like(wanja, X):- game(X).
Тут отсечение отбросит рассмотрение другого правила, если игра – баскетбол, а fail вызовет неуспех.
Этот пример показывает, что желательно иметь унарный предикат not, такой, что not(Цель) будет истиной в случае, когда Цель является ложью. На Прологе его можно описать так:
not(P):- P,!, fail;
true.
Пролог-система имеет встроенный предикат not, реализованный подобным образом.
Тогда пример можно переписать следующим образом:
like(wahja,X):- game(X),
not(basketball(X))
Важно отметить: предикат not выполняется успешно, когда подцель не является истиной, т.е. тогда, когда ассоциированная с ним подцель не может дать истину.
Следующая программа показывает использование предиката not.
domains
name = symbol
gpa = real
predicates
honor_student(name)
student(name, gpa)
probation(name)
clauses
honor_student(Name):-
student(Name, GPA),
GPA>=3.5,
not(probation(Name)).
student("Betty Blue", 3.5).
student("David Smith", 2.0).
student("John Johnson", 3.7).
probation("Betty Blue").
probation("David Smith").
На запрос honor_student(Name) она выдаст список студентов, средний балл которых больше или равен 3,5 за исключением студентов Betty Blue и David Smith, которые проходят практику.
4.Трудности в использовании отсечения и отрицания
Отметим сначала достоинства использования отсечения:
1. С помощью предиката cut можно повысить эффективность программы.
2. Используя cut, можно описать взаимоисключающие правила, поэтому существует возможность запрограммировать утверждения типа: если P, то Q, иначе R.
Ограничения на использование отсечения выходят за пределы декларативной стороны Пролог-программы. Если в программе нет отсечения, то можно менять порядок фактов и целей. Когда же предикат cut присутствует в программе, то изменение порядка фактов может выйти на её декларативное изменение (дать другое решение).
Если исключение отсечения из программы не меняет её декларативный смысл, то такое отсечение называют «зелёным». В другом случае отсечение называют «красным».
Работать с отрицанием также нужно с осторожностью. Трудности возникают потому, что отрицание, которое здесь используется, не полностью соответствует математическому отрицанию.
Если задать системе следующий запрос:
цель: not(dog(baks)),
она возможно ответит „да”. Однако этот ответ нельзя рассматривать как утверждение о том, что „Бакс не собака”. Просто системе не достаточно информации для подтверждения высказывания „Бакс - собака”. Такой подход берёт своё начало от предположения о замкнутости мира. Согласно данному предположению мир замкнут в том смысле, что всё существующее в нем либо указано в программе, либо может быть выведено из неё. И в другом случае, когда чего-то нет в программе (или не может быть выведено), то оно является ложным, и следовательно будет истинным его отрицание.
Мы же традиционно не считаем мир замкнутым: если в программе явно не указано, что dog(baks), то это не означает, что мы хотим сказать: Бакс не собака.
Приведём ещё один пример осторожного применения not:
predicates
r(symbol)
g(symbol)
p(symbol)
clauses
r(a).
g(b).
p(X):-not(r(X)).
На запрос цель: g(X), p(X) система ответит X=b, а на цель: p(X),g(X) – no (нет). Вся разница в том, что в первом случае переменная Х в момент обработки p(X) была уже связанной, а в другом – этого ещё не произошло.