А.4.3.
Разработка правил
В этом разделе
мы рассмотрим набор правил, который помогает справиться с вырожденной формулировкой
Р0 задачи о лжецах и правдолюбцах. Первые два правила, unwrap-true и
unwrap-false, извлекают содержимое высказывания в предположении, что персонаж,
которому принадлежит высказывание, является соответственно правдолюбцем или
лжецом, и на этом основании формируют объект claim.
;; Извлечение содержимого высказывания,
(defrule
unwrap-true
(world (tag ?N) (scope truth))
(statement
(speaker ?X) (claim $?Y) (tag ?N)) =>
(assert
(claim (content Т ?Х) (reason ?N)
(scope
truth)))
(assert (claim (content $?Y) (reason ?M)
(scope
truth)))
)
(defrule
unwrap-false
(world
(tag ?N) (scope falsity))
(statement
(speaker ?X) (claim $?Y) (tag ?N)) =>
(assert (claim (content F ?X) (reason ?N)
(scope
falsity)))
(assert
(claim (content NOT $?Y) (reason ?N)
(scope
falsity)) )
В каждом из
приведенных правил первый оператор в условной части делает предположение соответственно
о правдивости или лживости персонажа, а второй оператор в заключительной части
правила распространяет предположение на формируемые утверждения — объекты claim.
Далее нам
понадобятся правила, которые введут отрицания в выражения. Поскольку —<Т(А)
эквивалентно F(A), a —F(A) эквивалентно Т(А), то правила,
выполняющие соответствующие преобразования, написать довольно просто. Анализ
результатов применения этих правил значительно упростит выявление противоречий,
следующих из определенного предположения.
;;
Правила отрицания (defrule notl
?F
<- (claim (content NOT Т ?Р)) =>
(modify
?F (content F ?P))
)
(defrule
not2
?F
<- (claim (content NOT F ?P)) =>
(modify
?F (content Т ?Р))
)
;; Выявление противоречия между предположением о
;; правдивости и следующими из него фактами,
(defrule
contra-truth
(declare
(salience 10))
?W
<- (world (tag ?N) (scope truth))
?S
<- (statement (speaker ?Y) (tag ?N))
?P
<- (claim (content Т ?Х) (reason ?N) (scope truth))
?Q
<- (claim (content F ?X) (reason ?N) (scope truth)) =>
(printout
t crlf
"Statement is inconsistent if " ?Y " is a knight."
;;
"Высказывание противоречиво, если " ?Y " правдолюбец."
t
crlf)
(retract
?Q)
(retract
?P)
(modify
?W (scope falsity)) )
Если предположить,
что исходное высказывание было правдивым, то в дальнейшем обнаруживается противоречивая
пара утверждений, которые затем удаляются из рабочей памяти, а значение "правдивости"
предположения в объекте world изменяется на falsity (лживость). Если же после
этого также будет обнаружено противоречие, то мы приходим к выводу о глобальной
несовместимости условий задачи, т.е. в данной постановке мы имеем дело с логическим
парадоксом.
;; Выявление противоречия между предположением о
;;
лживости и следующими из него фактами, (defrule contra-falsity
(declare
(salience 10))
?W
<- (world (tag ?N) (scope falsity))
?S
<- (statement (speaker ?Y) (tag ?N))
?P
<- (claim (content F ?X) (reason ?N) (scope falsity))
?Q <- (claim (content T ?X) (reason ?N)
(scope
falsity)) => (printout t crlf
"Statement is inconsistent if " ?Y " is a knave. "
;; "Высказывание противоречиво, если " ?Y " лжец." t crlf)
(modify
?W (scope contra))
Правило sweep
обеспечивает проверку, все ли следствия из неверного предположения удалены
из памяти.
;;
Удалить из базы фактов все утверждения,
;;
которые следуют из предположения о правдивости.
(defrule
sweep
(declare
(salience 20))
(world
(tag ?N) (scope falsity))
?F
<- (claim (reason ?N) (scope truth)) =>
(retract
?F)
Обратите внимание
на то, что правила contra-truth, contra-f alsity и sweep имеют более высокий
приоритет (значение параметра salience), чем другие правила. Этим обеспечивается
как можно более ранее обнаружение противоречия, а следовательно, и удаление
из базы фактов утверждений, сделанных на основе предположения, приведшего к
противоречию.
Если теперь
запустить на выполнение программу, представив ей исходный набор фактов, соответствующих
условию задачи РО, то программа обнаружит, что оба контекста противоречивы.
Другими словами, независимо от того, предполагаем ли мы, что А говорит правду
или лжет, программа обнаружит противоречие в контексте world. Трассировка программы
в этом случае представлена в листинге А. 1. Строки, выведенные курсивом, — сообщения
основной программы, а прочие — сообщения программы трассировки. Для удобства
строки, указывающие на активизацию правил, представлены полужирным шрифтом.
Листинг
А.1. Трассировка решения задачи Р0
CLIPS>
(reset)
==>
f-0 (initial-fact)
==>
f-1 (world (tag 1) (scope truth))
==> f-2 (statement (speaker A)
(claim
F A) (reason 0) (tag 1))
CLIPS>
(run)
FIRE
1 unwrap-true: f-1,f-2
Assumption:
A
is a knight, so (T A) is true.
==> f-3 (claim (content F A) (reason 1)
(scope truth))
==> f-4 (claim (content T A) (reason 1)
(scope truth)) FIRE 2 contra-truth:
f-1, f-2, f-4, f-3
Statement is inconsistent if A is a knight.
<== f-3 (claim (content F A) (reason 1)
(scope truth)) <== f-4 (claim (content T A)
(reason 1) (scope truth)) <== f-1 (world (tag 1)
(scope truth)) ==> f-5 (world (tag 1)
(scope falsity)) FIRE 3 unwrap-false:
f-5,
f-2 Assumption
A
is a knave, so (T A) is false.
==> f-6 (claim (content NOT F A)
(reason
1) (scope falsity))
==>
f-7 (claim (content F A) (reason 1) (scope falsity))
FIRE
4 not2: f-6
<==
f-6 (claim (content NOT F A) (reason 1) (scope falsity))
==>
f-8 (claim (content Т A) (reason 1) (scope falsity))
FIRE
5 contra-falsity: f-5, f-2, f-7, f-8
Statement
is inconsistent if A is a knave.
<==
f-5 (world (tag 1) (scope falsity))
==>
f-9 (world (tag 1) (scope contra))
Упражнение
1
Читателям,
желающим самостоятельно поэкспериментировать с этой программой, я предлагаю
рассмотреть другой вырожденный случай головоломок этого класса.
Предположим,
что персонаж А утверждает: "Я всегда говорю правду". К какой категории
следует отнести этот персонаж?
В такой
постановке задача имеет неоднозначное решение. Предположение, что А правдолюбец,
не приводит нас к противоречию. Но точно так же не приводит к противоречию
и предположение, что А —лжец.
Ваша задача—
модифицировать описанную выше программу таким образом, чтобы она давала заключение,
что оба контекста непротиворечивы. Один из возможных вариантов модификации —
ввести в состав программы правила consist-truth и consist-falsity, разработав
их по образцу правил contra-truth и contra-falsity. Эти правила должны дать
пользователю знать, что при данном предположении противоречий не обнаружено,
причем правила должны активизироваться в случае, когда нет больше правил, претендующих
на внимание интерпретатора.
Обратите внимание на то, что в задачах этого класса недостаточно убедиться, что начальное предположение об истинности некоторого высказывания не приводит к противоречию. Необходимо еще и проверить, приведет ли к противоречию обратное предположение. Если окажется, что оно также непротиворечиво, значит, задача не имеет единственного решения.