- •Введение
- •1. История Пролога
- •2. Синтаксис и семантика Пролог-программ
- •2.1. Объекты данных1
- •2.2. Декларативный смысл Пролог-программ
- •2.3. Основные определения
- •3. Практическое программирование на Прологе
- •3.1. Структура Пролог-программы
- •3.2. Некоторые предопределенные термы
- •3.3. Свободные и связанные переменные
- •3.4. Внутренняя бд Пролога
- •3.5. Обработка условий и организация циклов в Prolog’е
- •3.5.1. Обработка условия
- •3.5.2. Использование предиката типа repeat
- •3.6. Списки в Прологе
- •3.6.1. Примеры списков
- •3.6.2. Разделение списков на голову и хвост
- •3.6.3. Некоторые полезные программы для работы со списками
- •1. Слияние списков.
- •2. Сортировка списков
- •3.7. Ввод и вывод
- •3.7.1. Файловая система
- •Операции с именами файлов
- •Чтение и запись
- •3.8. Строки и функции работы со строками
- •4. Простенькая экспертная система
- •Игрушечная эс «Кто чем увлекается?»
- •5. Базовые понятия и термины Пролога
- •5.1. Объекты
- •5.2. Внутренние дела Пролога
- •5.3. Что такое шаблоны?
- •5.4. Управление поиском
- •Литература
4. Простенькая экспертная система
Задача этой главы заключается в том, чтобы проиллюстрировать использование Пролога для создания игрушечной экспертной системы.
Игрушечная эс «Кто чем увлекается?»
Мы хотим создать систему, которая отвечала бы на вопросы, сформулированные на русском языке, на тему увлечений (hobby) действующих лиц.
Начнем с простейшего варианта.
В простейшем варианте нам следует создать элементарную базу фактов типа увлечение(Кто,Что). Все вербальные варианты запросов система проинтерпретирует так:
1) если в тексте вопроса присутствует значение «Кто» (Петров, Сидоров,...), следует выдать все значения «Что»;
2) если в тексте вопоса присутствует значение «Что», следует выдать все значения «Кто»;
3) если в тексте запроса присутствуют «Что» и «Кто», то система интерпретирует запрос, как «Увлекается ли Кто Что?».
Ответ: «Да» или «Нет» в зависимости от содержания элементарной базы знаний.
В таком простейшем варианте ЭС (с единственным видом отношения между субъектом и объектом) можно не утруждать пользователя формулированием запроса в полном виде, играя в понимание, а предоставить ему возможность выбрать тип запроса и заполнить соответствующие поля.
Алгоритм обработки запросов очень прост. В самом сложном случае, когда их типы заранее не определены (через меню выбора типа), каждое слово запроса проверяется на принадлежность типам «Кто» или «Что» и, в зависимости от результата, формулируется ответ. «Закодируем» алгоритм обработки строки-запроса Запрос, полагая, что база знаний содержится в файле «hobbyNew.dbs».
Программа завершает работу, если в ответ на ее вопрос write(«Есть вопросы? (Д|Н|д|н)»), пользователь ответит 'Н' или 'н'. Предикат repeat используется в разделе goal для организации цикла по обработке вопросов.
domains
кто=symbol
что=symbol
facts - f1
увлечение(кто,что)
кто(кто)
что(что)
predicates
nondeterm repeat
nondeterm ответить(symbol)
ответить_что(кто)
ответить_кто(что)
анализ_КтоЧто(symbol)
спросить
goal
consult("hobbyNew.dbs",f1),
repeat,
спросить,
retractall(кто(_)),
retractall(что(_)),
write("Есть вопросы? (Д|Н)"),
readchar(ДаНет),
ДаНет='Н',exit().
clauses
repeat.
repeat:-repeat.
ответить(""):-
кто(Кто),
что(Что),
увлечение(Кто,Что),!,
write("Да");
кто(Кто),
что(Что),
not(увлечение(Кто,Что)),!,
write("Нет");
кто(Кто),
not(что(_)),!,
write(Кто,".Хобби:"),nl,
ответить_что(Кто);
что(Что),
not(кто(_)),!,
write(Что," является увлечением для:"),nl,
ответить_кто(Что);
!,write("Не понял"),nl.
ответить(Запрос):-
fronttoken(Запрос,Лексема,Остаток),!,
анализ_КтоЧто(Лексема),
ответить(Остаток).
анализ_КтоЧто(Лексема):-
увлечение(Лексема,_),!, assert(кто(Лексема));
увлечение(_,Лексема),!, assert(что(Лексема));
!.
ответить_кто(Что):-
увлечение(Кто,Что),
write(Кто),nl,
fail.
ответить_кто(_).
ответить_что(Кто):-
увлечение(Кто,Что),
write(Что),nl,
fail.
ответить_что(_).
спросить:-
write("Введите Ваш вопрос:"),nl,
readln(Вопрос),
ответить(Вопрос),!;
!.
Теперь усложним задачу с целью дать возможность пользователю формулировать вопрос грамматически правильно, а также для того, чтобы вводить любые виды отношений. Факты мы приведем к универсальному виду f(объект1,отношение,объект2), а также введем синонимы для имен объектов и отношений. В данном случае под термином синоним будем понимать как грамматическое видоизменение слова, так и другое слово, которое мы считаем семантически эквивалентным исходному.
При данной организации БЗ и приведенном ниже алгороитме обработки запроса, имена объектов и отношений,множества синонимов различных отношений и множество синонимов различных объектов не должны пересекаться. Например, если есть факты
ф("кирилл","хобби","шахматы")},
ф("кирилл","любить","татьяна")},
соб("татьяна",["татьяну",...])
сот("хобби",["нравится","увлекается","любит","любить"])
сот("любить",["любит"])
то на вопрос: "кирилл любит татьяну" Вы получите ответ "Нет!", поскольку в качестве имени отношения будет выбрано "хобби".
Состав базы знаний.
ф("кирилл","хобби","хоккей")
ф("петров","хобби","лыжи")
ф("ирина","хобби","кино")
ф("татьяна","хобби","гимнастика")
ф("кирилл","хобби","гимнастика")
ф("петров","любить","ирина")
ф("ирина","любить","кирилл")
ф("кирилл","любить","татьяна")
соб("кирилл",["кириллу","кириллом","кирилла","кирилле"])
соб("петров",["петрову","петровым","петрова","петрове"])
соб("ирина",["ирине","ириной","ирины","ирину"])
соб("гимнастика",["гимнастикой","гимнастики","гимнастикой",
"гимнастике","гимнастику"])
соб("татьяна",["татьяне","татьяной","татьяны","татьяну"])
сот("хобби",["нравится","увлекается"])
сот("любить",["любит"])
Текст программы.
domains
список=symbol*
facts - f1
ф(symbol,symbol,symbol)
соб(symbol,список)
сот(symbol,список)
кто(symbol)
что(symbol)
отн(symbol)
временно(symbol)
predicates
nondeterm repeat
nondeterm ответить(symbol)
ответ1(symbol,symbol,symbol)
ответ2(symbol,symbol)
ответ3(symbol,symbol)
ответ4(symbol)
ответ5(symbol,symbol)
ответ6(symbol)
ответ7(symbol)
анализ_КтоОтношениеЧто(symbol)
nondeterm поиск_кто(symbol)
nondeterm поиск_что(symbol)
nondeterm поиск_отношения(symbol)
искать_синоним_кто(symbol)
искать_синоним_отношения(symbol)
искать_синоним_что(symbol)
загрузить_список(список)
спросить
goal
consult("hobbyNew2.dbs",f1),
repeat,
спросить,
retractall(кто(_)),
retractall(что(_)),
retractall(отн(_)),
write("Есть вопросы? (Д|Н)"),
readchar(ДаНет),
ДаНет='Н',!,exit().
clauses
repeat.
repeat:-repeat.
ответить(""):-
кто(Кто),
что(Что),
отн(Отношение),!,
ответ1(Кто,Отношение,Что);
кто(Кто),
что(Что),
not(отн(_)),ф(Кто,_,Что),!,
ответ2(Кто,Что);
кто(Кто),
отн(Отношение),
not(что(_)),!,
ответ3(Кто,Отношение);
кто(Кто),
not(отн(_)),
not(что(_)),!,
ответ4(Кто);
not(кто(_)),
отн(Отношение),
что(Что),!,
ответ5(Отношение,Что);
not(кто(_)),
отн(Отношение),
not(что(_)),!,
ответ6(Отношение);
not(кто(_)),
not(отн(_)),
что(Что),!,
ответ7(Что);
!,write("Не понял"),nl.
ответить(Запрос):-
fronttoken(Запрос,Лексема,Остаток),
анализ_КтоОтношениеЧто(Лексема),
ответить(Остаток).
анализ_КтоОтношениеЧто(Лексема):-
поиск_кто(Лексема),!;
поиск_отношения(Лексема),!;
поиск_что(Лексема),!;
!.
поиск_кто(Лексема):-
not(кто(_)),
ф(Лексема,_,_),!,assert(кто(Лексема));
not(кто(_)),искать_синоним_кто(Лексема),!;!,fail.
поиск_отношения(Лексема):-
not(отн(_)),
ф(_,Лексема,_),!,assert(отн(Лексема));
not(отн(_)),искать_синоним_отношения(Лексема),!;!,fail.
поиск_что(Лексема):-
not(что(_)),
ф(_,_,Лексема),!,assert(что(Лексема));
not(что(_)),искать_синоним_что(Лексема),!;!,fail.
искать_синоним_кто(Лексема):-
соб(Кто,СписокКто),
загрузить_список(СписокКто),
временно(Лексема),!,
retractall(временно(_)),assert(кто(Кто));
fail.
искать_синоним_кто(_):-retractall(временно(_)),!,fail.
искать_синоним_отношения(Лексема):-
сот(Отн,СписокОтн),
загрузить_список(СписокОтн),
временно(Лексема),!,
retractall(временно(_)),assert(отн(Отн));
fail.
искать_синоним_отношения(_):-retractall(временно(_)),!,fail.
искать_синоним_что(Лексема):-
соб(Что,СписокЧто),
загрузить_список(СписокЧто),
временно(Лексема),!,
retractall(временно(_)),assert(что(Что));
fail.
искать_синоним_что(_):-retractall(временно(_)),!,fail.
загрузить_список([]).
загрузить_список([H|T]):-
assert(временно(H)),загрузить_список(T).
ответ1(Кто,Отношение,Что):-
ф(Кто,Отношение,Что),!,
write("otvet1"),nl,
write("Да."),nl;!,write("Нет."),nl.
ответ2(Кто,Что):-
ф(Кто,Отношение,Что),
write("otvet2"),nl,
write(Кто," ",Отношение," ",Что),nl,
fail.
ответ2(_,_).
ответ3(Кто,Отношение):-
ф(Кто,Отношение,Что),
write("otvet3"),nl,
write(Кто," ",Отношение," ",Что),nl,
fail.
ответ3(_,_).
ответ4(Кто):-
ф(Кто,Отношение,Что),
write("otvet4"),nl,
write(Кто," ",Отношение," ",Что),nl,
fail.
ответ4(_).
ответ5(Отношение,Что):-
ф(Кто,Отношение,Что),
write("otvet5"),nl,
write(Кто," ",Отношение," ",Что),nl,
fail.
ответ5(_,_).
ответ6(Отношение):-
ф(Кто,Отношение,Что),
write("otvet6"),nl,
write(Кто," ",Отношение," ",Что),nl,
fail.
ответ6(_).
ответ7(Что):-
ф(Кто,Отношение,Что),
write("otvet7"),nl,
write(Кто," ",Отношение," ",Что),nl,
fail.
ответ7(_).
спросить:-
write("Введите Ваш вопрос:"),nl,
readln(Вопрос),
upper_lower(Вопрос,Q),
ответить(Q),!;
!.
Протокол сеанса с системой (знак '?' опущен, а также опущены вопросы системы в отношении продолжения диалога):
Любит ли Кирилл Татьяну
otvet1
Да.
Любит ли Татьяна Кирилла
Нет.
В каких отношениях находятся Петров и Ирина
otvet2
петров любить ирина
Кого любит Ирина
otvet3
ирина любить кирилл
Как относится Татьяна к гимнастике
otvet2
татьяна хобби гимнастика
Все о Петрове
otvet4
петров хобби лыжи
otvet4
петров любить ирина
Кто любит кино
Есть вопросы? (Д|Н)Введите Ваш вопрос:
Чьим хобби является кино
otvet5
ирина хобби кино
Кто чем увлекается
otvet6
кирилл хобби хоккей
otvet6
петров хобби лыжи
otvet6
ирина хобби кино
otvet6
татьяна хобби гимнастика
otvet6
кирилл хобби гимнастика
Кто занимается гимнастикой
Есть вопросы? (Д|Н)Введите Ваш вопрос:
(Комментарий: в синонимах нет слова гимнастикой)