Усовершенствованная версия оболочки позволяет также успешно вести диалоги и с другой стороны. Когда программа задает вопрос, пользователь может ответить своим собственным вопросом “почему?”. Естественным ответом оболочки должно быть правило, на основании которого программа пытается сделать вывод. Такую возможность легко ввести в оболочку, расширяя все отношения дополнительным аргументом - используемым текущим правилом. Поскольку в Пролог-программах доступ к глобальному состоянию процесса вычислений невозможен, это правило должно быть явно представлено в дополнительном аргументе.
Интерфейс для обеспечения ответа на вопрос “почему?” реализуется дополнительными правилами предиката respond. Предикат respond переписывает текущее родительское правило и приглашает пользователя ответить еще раз. Формат, в котором будет представлено это правило, определяется предикатом display_rule, позволяющим пользователю представлять правила в удобной для него форме.
Повторные ответы на вопрос “почему?”, использующие предложение respond, приводят к повторной переформулировке родительского правила. Решение состоит в выдаче прародительского правила в ответ на второй вопрос “почему?”, прапрародительского правила в ответ на третье “почему?” и так далее вверх по дереву поиска. С этой целью дополнительный аргумент содержит список правил, учитывающих предысторию.
Для учета случая, когда все правила для ответа исчерпаны, необходимо дополнительное предложение.
Трудности возникают, когда приходится объяснять использования правила A в процессе доказательства not(A). В этом случае предыстория вывода теряется, и аргумент Rules в третьем предложении respond становится неконкретизованной переменной.
% программа 7
:- multifile system/1, askable/1.
:- dynamic untrue/1.
% дополнительный аргумент - список содержащий текущее
% родительское правило и правила из предыстории
solve(true,_):-!.
solve((A,B),Rules):-!,
solve(A,Rules),
solve(B,Rules).
solve(not(A),_):-!,
not(solve(A,_)).
solve(A,Rules):-
not system(A),
clause(A,B),
solve(B,[rule(A,B)|Rules]).
solve(A,_):-
system(A),
A.
solve(A,Rules):-
askable(A),
not known(A),
ask(A,Answer),
respond(Answer,A,Rules).
system(is(_,_)).
system(_=_).
system(_<_).
system(_>_).
system(write(_)).
system(nl).
ask(A,Answer):-
display_query(A),
read(Answer).
% дополнительный аргумент - список содержащий текущее
% родительское правило и правила из предыстории
respond(yes,A,_):-
assert(A).
respond(no,A,_):-
assert(untrue(A)),fail.
% три дополнительных правила для respond
respond(why,A,Rules):-
var(Rules),!,
write(' хочу использовать ложность '),
write(A),nl,
ask(A,Answer),
respond(Answer,A,[]).
respond(why,A,[Rule|Rules]):-
write(' хочу воспользоваться правилом:'),
display_rule(Rule),
ask(A,Answer),
respond(Answer,A,Rules).
respond(why,A,[]):-
write(' <== возможности объяснения исчерпаны '),nl,
ask(A,Answer),
respond(Answer,A,[]).
known(A):-A,!.
known(A):-
untrue(A).
display_query(A):-
write(A),
write('?').
display_rule(rule(A,B)):-
nl,write('Если '),
write_conjunction(B),
write(' то '),
write(A),nl.
write_conjunction((A,B)):-
!,write(A),write(' и '),
write_conjunction(B).
write_conjunction(A):-
write(A),nl.
Вторым аргументом предиката solve(Goal,Rules) в программе 7 является список правил, используемых для редукции предковых вершин цели Goal в текущем дереве доказательства. Список правил обновляется с помощью предиката solve в процессе редукции цели. Для представления правила выбрана структура rule(A,B). Единственным предикатом, на который влияет выбор представления правила, является предикат display_rule.
Выясним рекомендации для Боба:
?- solve(hy(bob,Y),[]).
bob имеет симптом мышечные боли? why.
хочу воспользоваться правилом:
Если bob имеет симптом мышечные боли и bob имеет симптом лихорадка
то bob имеет простуда
bob имеет симптом мышечные боли? why.
хочу воспользоваться правилом:
Если bob имеет простуда и not bob имеет уязвимый возраст
то bob - рекомендовано лечь в постель и принять аспирин
bob имеет симптом мышечные боли? why.
хочу воспользоваться правилом:
Если member(лечь в постель и принять аспирин,
[лечь в постель и принять аспирин,вызвать врача])
и bob - рекомендовано лечь в постель и принять аспирин
то hy(bob, лечь в постель и принять аспирин)
bob имеет симптом мышечные боли? why.
<== возможности объяснения исчерпаны
bob имеет симптом мышечные боли? yes.
bob имеет симптом лихорадка? yes.
bob имеет признак моложе 8 лет? no.
bob имеет признак старше 60 лет? no.
Y = 'лечь в постель и принять аспирин' ;
bob имеет симптом насморк? why.
хочу воспользоваться правилом:
Если bob имеет симптом насморк и bob имеет симптом мышечные боли
и not bob имеет симптом лихорадка
то bob имеет грипп
bob имеет симптом насморк? yes.
bob имеет симптом нарывы в горле? why.
хочу воспользоваться правилом:
Если bob имеет симптом лихорадка и bob имеет симптом нарывы в горле
то bob имеет острый фарингит
bob имеет симптом нарывы в горле? yes.
Y = 'вызвать врача' ;
No
|