write( 'Это правда: ');
write( 'Есть (еще) решения для :' )),
write( Вопрос), write( '?'),
принять( Ответ1), !, % Ответ1 - да/нет/почему
обработать( Ответ1, Цель, Вопрос, Перем,
Трасса, Ответ, N).
обработать( почему, Цель, Вопрос, Перем,
Трасса, Ответ, N):-
выд_трассу( Трасса),
спросить( Цель, Вопрос, Перем, Трасса, Ответ, N).
обработать( да, Цель,_, Перем, Трасса, правда, N) :-
след_индекс( Инд),
% Получить новый индекс для "сказано"
Инд1 is Инд + 1,
( запрос_перем( Перем),
assertz( сказано( Цель, правда, Инд) );
% Запись решения
копия( Цель, Копия), % Копирование цели
ответпольз( Цель, Копия, Трасса, Ответ, Инд1) ).
% Есть еще решения?
обработать( нет, Цель, _, _, _, ложь, N) :-
копия( Цель, Копия),
сказано( Копия, правда, _), !,
% 'нет' означает, больше нет решений
assertz( конец_ответов( Цель) ),
% Отметить конец ответов
fail;
след_индекс( Инд),
% Следующий свободный индекс для "сказано"
assertz( сказано( Цель, ложь, Инд) ).
% 'нет' означает нет ни одного решения
формат( Пер, Имя, Имя, Перем, [Пер/Имя | Перем]) :-
var( Пер), !.
формат( Атом, Имя, Атом, Перем, Перем) :-
atomic( Атом), !,
atomic( Имя).
формат( Цель, Форм, Вопрос, Перем0, Перем) :-
Цель =.. [Функтор | Apг1],
Форм =.. [Функтор | Форм1],
формвсе( Apг1, Форм1, Арг2, Перем0, Перем),
Вопрос =.. [Функтор | Арг2].
формвсе( [], [], [], Перем, Перем).
формвсе( [X | СпХ], [Ф | СпФ], [В | СпВ], Перем0, Перем) :-
формвсе( СпХ, СпФ, СпВ, Перем0, Перем1),
формат( X, Ф, В, Перем1, Перем).
запрос_перем( []).
запрос_перем( [Переменная/Имя | Переменные]) :-
nl, write( Имя), write( '='),
read( Переменная),
запрос_перем( Переменные).
выд_трассу( []) :-
nl, write( 'Это был ваш вопрос'), nl.
выд_трассу( [Цель по Прав | Трасса] ) :-
nl, write( 'Чтобы проверить по' ),
write( Прав), write( ', что'),
write( Цель),
выд_трассу( Трасса).
конкретный( Терм) :-
нумпер( Терм, 0, 0). % Нет переменных в Терм'е
% конкретизация( Т1, Т2) означает, что Т2 - конкретизация Т1,
% т.е. терм Т1 - более общий, чем Т2, или той же степени
% общности, что и Т2
конкретизация( Терм, Терм1) :-
% Терм1 - частный случай Терм'а
копия( Терм1, Терм2),
% Копия Терм1 с новыми переменными
нумпер( Терм2, 0, _), !,
Терм = Терм2. % Успех, если Терм1 - частный случай Терм2
копия( Терм, НовТерм) :-
% Копия Терм' а с новыми переменными
asserta( copy( Терм) ),
retract( сору( НовТерм) ), !.
посл_индекс( 0). % Начальный индекс для "сказано"
след_индекс( Инд) :- % Следующий индекс для "сказано"
retract( посл_индекс( ПослИнд) ), !,
Инд is ПослИнд + 1,
assert( посл_индекс( Инд) ).
Рис. 14.11. Оболочка экспертной системы: Вопросы к пользователю и ответы на вопросы "почему".
Отношение, подобное нумпер
, часто входит в состав пролог-системы в качестве встроенной процедуры. Если это не так, то его можно реализовать программно следующим способом:
нумпер( Терм, N, Nплюс1) :-
var( Терм), !, % Переменная?
Терм = пер/N,
Nплюс1 is N + 1.
нумпер( Терм, N, М) :-
Терм =.. [Функтор | Аргументы], % Структура или атом
нумарг( Аргументы, N, M).
% Пронумеровать переменные в аргументах
нумарг( [], N, N) :- !.
нумарг( [X | Спис], N, M) :-
нумпер( X, N, N1),
нумарг( Спис, N1, М).
Процедура
выдать( Ответ)
приведенная на рис. 14.12, показывает пользователю окончательный результат консультационного сеанса и дает объяснения типа "как". Ответ
включает в себя как ответ на вопрос пользователя, так и дерево вывода, демонстрирующее как система пришла к такому заключению. Сначала процедура выдать
представляет пользователю свое заключение. Затем, если пользователь пожелает узнать, как это заключение достигнуто, то печатается дерево вывода в некоторой удобной для восприятия форме - это и есть объяснение типа "как". Форма объяснения показана в примере разд. 14.4.3.
14.5.5. Драйвер верхнего уровня
И наконец, для того, чтобы иметь удобный доступ к оболочке из интерпретатора Пролога, нам необходима процедура, выполняющая функцию "драйвера". На рис. 14.13 показано, как могла бы выглядеть предназначенная для этой цели процедура эксперт
. Драйвер эксперт
производит запуск трех основных модулей оболочки (рис. 14.10–14.12) и координирует их работу. Например:
Читать дальше