Программирование на языке ПРОЛОГ для искуственного интеллекта

       

Процедура ответпольз


Прежде чем перейти к написанию процедуры ответпольз, давайте рассмотрим одну полезную вспомогательную процедуру

        принять( Ответ)

В процессе диалога часто возникает ситуация, когда от пользователя ожидается ответ "да", "нет" или "почему". Процедура принять предназначена для того, чтобы извлечь один из этих ответов, понимая его правильно и в тех случаях, когда пользователь применяет сокращения ('д' или 'н') или делает ошибки. Если ответ пользователя непонятен, то принять просит дать другой вариант ответа.

        принять( Ответ) :-
                read( Ответ1),
                означает( Ответ1, Значение),  !,

                                                            % Ответ1 означает что-нибудь?
                Ответ = Значение;         % Да
                nl, write( 'Непонятно, попробуйте еще раз,      % Нет
                                                        пожалуйста'),   nl,
                принять( Ответ).           % Новая попытка


        означает( да, да).
        означает( д, да).


        означает( нет, нет).
        означает( н, нет).
        означает( почему, почему).
        означает( п, почему).


Следует заметить, что процедурой принять нужно пользоваться с осторожностью, так как она содержит взаимодействие с пользователем. Следующий фрагмент программы может служить примером неудачной попытки запрограммировать интерпретацию ответов пользователя:

        принять( да), интерп_да( ...);
        принять( нет), интерп_нет( ...);
        . . .


Здесь, если пользователь ответит "нет", то программа попросит его повторить свой ответ. Поэтому более правильный способ такой:

        принять( Ответ),
        ( Ответ = да, интерп_да( ...);
          Ответ = нет, интерп_нет( ...);
          ... )


        Процедура

        ответпольз( Цель, Трасса, Ответ)

спрашивает пользователя об истинности утверждения Цель. Ответ - это результат запроса. Трасса используется для объяснения в случае, если пользователь спросит "почему".

Сначала процедура ответпольз должна проверить, является ли Цель информацией, которую можно запрашивать у пользователя. Это свойство объекта Цель задается отношением

        можно_спросить( Цель)

которое в дальнейшем будет усовершенствовано. Если спросить можно, то утверждение Цель выдается пользователю, который, в свою очередь, указывает истинно оно или ложно. Если пользователь спросит "почему", то ему выдается Трасса.


Если утверждение Цель истинно, то пользователь укажет также значения содержащихся в нем переменных (если таковые имеются).

Все вышеизложенное можно запрограммировать (в качестве первой попытки) следующим образом:

        остветпольз( Цель, Трасса, Ответ) :-
                можно_спросить( Цель),
            % Можно ли спрашивать
                спросить( Цель, Трасса, Ответ).
                            % Задать вопрос относительно утверждения Цель

        спросить( Цель, Трасса, Ответ) :-
                показать( Цель),

                            % Показать пользователю вопрос
                принять(Ответ1),                        % Прочесть ответ
                обработать( Ответ1, Цель, Трасса, Ответ).
                            % Обработать ответ

        обработать( почему, Цель, Трасса, Ответ) :-
                            % Задан вопрос "почему"


                показать_трассу( Трасса),
                            % Выдача ответа на вопрос "почему"
                спросить( Цель, Трасса, Ответ).
                            % Еще раз спросить

        обработать( да, Цель, Трасса, Ответ) :-
                            % Пользователь ответил, что Цель истинна
                Ответ = правда,
                запрос_перем( Цель);

                            % Вопрос о значении переменных
                спросить( Цель, Трасса, Ответ).
                            % Потребовать от пользователя новых решений

        обработать( нет, Цель, Трасса, ложь).
                            % Пользователь ответил, что Цель ложна

        показать( Цель) :-


                nl, write( 'Это правда:'),
                write( Цель), write( ?), nl.


Обращение к процедуре запрос_перем( Цель) нужно для того, чтобы попросить пользователя указать значение каждой из переменных, содержащихся в утверждении Цель:

        запрос_перем( Терм) :-
                var( Терм),  !,
                 % Переменная ?
                nl, write( Терм), write( '='),
                read( Терм).
                   % Считать значение переменной

        запрос_перем( Терм) :-
                Терм =.. [Функтор | Аргументы],

                                % Получить аргументы структуры
        запрос_арг( Аргументы).
                                % Запросить значения переменных в аргументах

        запрос_арг( [ ]).

        запрос_арг( [Терм | Термы]) :-
                запрос_перем( Терм),


                запрос_арг( Термы).


Проведем несколько экспериментов с процедурой ответпольз. Пусть, например, известно, что пользователя можно спрашивать о наличии бинарного отношения ест:

        можно_спросить( X ест Y).

( В приведенных ниже диалогах между пролог-системой и пользователем тексты пользователя даются полужирным шрифтом, а реплики пролог-системы курсивом).

        ?-  ответпольз( питер ест мясо, [ ], Ответ).

            Это правда: питер ест мясо?          % Вопрос пользователю
            да.                                                         % Ответ пользователя

            Ответ = правда

Более интересный пример диалога (с использованием переменных) мог бы выглядеть примерно так:

        ?-  ответпольз( Кто ест Что, [ ], Ответ).

        Это правда: _17 ест _18?
                                % Пролог дает переменным свои внутренние имена
        да.
        _17 = питер.
        _18 = мясо.

        Ответ = правда.
        Кто = питер
        Что = мясо;         % Возврат для получения других решений

        Это правда: _17 ест _18?
        да.
        _17 = сьюзен.
        _18 = бананы.

        Ответ = правда
        Кто = сьюзен
        Что = бананы;

        Это правда : _17 ест _18?
        нет.

        Ответ = ложь


Содержание раздела