|
Пример написания программы Простая Экспертная Система на языке ПроЛог. Начнем с того, что знак равно в ПроЛоге используется не как оператор приравнивания, а как оператор унифицирования. Унификация – это приведение выражений справа и слева от знака унификации к одному значению. При этом несвязанные значения из одного выражения будут заполнены значениями из другого выражения. Таким образом, если в операции унификации участвуют две переменных, и каждая связана со своим значением, то выполняется их сравнение. Если одна переменная не связана, то выполняется приравнивание ей значения. А если в унификации участвуют выражения с наличием несвязанных частей, то эти части принимают значения из таких же частей другого выражения. При этом ПроЛог пытается привести оба выражения к одному значению. Примеры. Унификация как приравнивание. Goal А = 5, А = Б write(А, “,”, Б). Здесь в первой строчке унификация несвязанной переменной со значением 5. Результат – значение переменной А связано с константой 5. Во второй строчке унификация несвязанной переменной В и связанной А приведет к передаче значения переменной А в переменную Б. ПроЛог выдаст на экран: 5,5 Унификация как сравнение Goal А = 5, Б = “да”, А = Б. Здесь уже в унификации будут участвовать два полностью связанных значения, значит происходит простое сравнение значений. Результат выполнения ПроЛога: No Это говорит что унификация не успешна, то есть значения переменной А и Б неравны. Унификация как приведение к одному значению Теперь посмотрим что будет, если в переменных будут только некоторые части значений несвязанны. Для это хорошо подходит список значений. Если какой-либо элемент списка несвязан, то механизм унификации будет пытаться его связать используя значения из другого выражения. domains Слово = string Слова = reference Слово* predicates унификация(Слова А, Слова Б) clauses унификация(Слова,Слова):-!. Goal А = [“да”, “нет”, С], Б = [“да”,_, “точно”], унификация ( А, Б), write(А, “,”, Б, “:”, С). Здесь ПроЛог будет приводить оба значения к одному обобщенному значению, используя связанные значения из одного выражения для связи несвязанных значений в другом выражении. Результат выполнения ПроЛога: [“да”, “нет”, “точно”], [“да”, “нет”, “точно”]: “точно” Как видно унификация прошла успешно, что привело к одному значению для обоих выражений. Однако, если переменной А будет присвоено другое значение [“да”, “нет”,_,_], унификация будет неуспешна. Нужно заметить, что для включения механизма унификации неполных значений нужно объявить явно, что значения переменной могут быть частично связаны (быть ссылками, а не значениями) с помощью ключевого слова reference. Это делается при объявлении типа значения в секции domains программы. Еще замечание. При появлении в программе ПроЛога константы “список элементов”, первый элемент должен быть связан со значением. Это нужно для того чтобы ПроЛог мог определить тип остальных элементов списка. В нашем примере в обоих константах “список элементов” первый элемент звязан со значением “да”. Если список передается как параметр вызова предиката, то это условие необязательно ввиду того что параметры предиката уже явно описаны и принадлежат к конкретному типу. Например, можно было бы написать предикат унификация([_, “да”],С) что не вызвало бы ошибку ПроЛога. Еще интересная особенность ключевого слова reference – это то, что можно унифицировать еще несвязанные переменные. Тогда их ссылки на область значения будут одинаковые. И если в дальнейшем одну переменную связать со значением, то и вторая переменная будет автоматически связана. Пример с использованием предиката “унификация”, описанного выше. Goal Унификация ( А, Б), А = [“да”, “нет”], write(Б). Результат ПроЛога : [“да”, “нет”] Видно, что явно никакого значения переменной Б не присваивалось. Тем не менее в ней появилось значение. Простая Экспертная Система на основе унификации значений ПроЛога. Теперь Мы можем создать более сложный и интересный пример использования унификаций значений ПроЛога. Сделаем экспертную систему по знаниям о мире на языке, приближенном к естественному языку человека. Пусть каждое знание состоит только из одного предложения. Каждое слово предложения может быть разного типа: существительное, глагол, прилагательное,… Каждое слово имеет семантическую связь в другому слову. Объявление такого слова будет выглядеть так: Domains Слово = string СловоПредл = reference сущ(Слово,СловоПредл); глаг(Слово,СловоПредл); прил(Слово,СловоПредл); пред(Слово,СловоПредл); нар(Слово,СловоПредл); пусто Здесь “пусто” означает конец предложения. Как видно каждое слово предложения связано с другим словом предложения, так что бы смысл знания был выражен семантически с помощью этих связей. Теперь опишем базу знаний и вид фактов в ней. database - знания знание(СловоПредл) Используя унификацию значений ПроЛога Мы получаем наипростейший поиск знаний. Предикат поиска будет выглядеть так: predicates nondeterm ответ(СловоПредл) clauses ответ(СловоПредл):- знание(СловоПредл). ВСЁ! Замечу, что можно обойтись и без предиката вовсе, задавая поиск фактов напрямую в базе знаний. Ключевое слово nondeterm указывает на то что в случае отката нужно перебирать все возможные варианты ответов если таковые есть. Теперь можно создать бузу знаний для экспертной системы и задавать вопросы. Пусть база знаний хранится в файле “знания.txt” и содержит факты: знание(сущ("лев",глаг("живёт",пред("в",сущ("саванне",пусто))))).знание(сущ("антилопа",глаг("живёт",пред("в",сущ("саванне",пусто))))).знание(сущ("зебра",глаг("живёт",пред("в",сущ("саванне",пусто))))).знание(сущ("лев",глаг("охотится",пред("на",сущ("животных",пусто))))).знание(сущ("тигр",глаг("охотится",пред("на",сущ("животных",пусто))))).знание(сущ("тигр",глаг("живёт",пред("в",сущ("лесу",пусто))))).знание(сущ("заяц",глаг("живёт",пред("в",сущ("лесу",пусто))))).знание(сущ("заяц",глаг("ест",сущ("траву",пусто)))).знание(сущ("олень",глаг("ест",сущ("траву",пусто)))).знание(сущ("заяц",глаг("ест",сущ("кору",пусто)))). Теперь можно задать вопрос экспертной системе, например, кто живёт в саванне. Это будет выглядеть следующим обращом: Goal:- % вызов решателя ПроЛога consult("знания.txt",знания), % загрузка базы знаний% определение слов вопроса ЧтоДелает="живёт", Где="саванне", % сборка вопроса А=сущ(Кто,глаг(ЧтоДелает,пред(Предл,сущ(Где,Дополнения)))), % поиск ответов ответ(А), % печать ответов nl,write(Кто, " ", ЧтоДелает, " ", Предл, " ", Где, " ", Дополнения), fail. Ответ Пролога: лев живёт в саванне пусто антилопа живёт в саванне пусто зебра живёт в саванне пусто Если нам нужно узнать что делает лев, то нужно задать вместо слов запроса, сборки запроса и вывода на экран следующие строчки: Кто="лев", А=сущ(Кто,глаг(ЧтоДелает,Дополнения), nl,write(Кто, " ", ЧтоДелает, " ", Дополнения), ответ ПроЛога будет: лев живёт пред("в",сущ("саванне",пусто))лев охотится пред("на",сущ("животных",пусто)) Конечно можно сделать автоматическую сборку вопроса и вывод найденных знаний без вывода внутренних типов слов знания, так чтобы полностью перейти на естественный язык общения с экспертной системой. Но это уже другая задача. Вообще на основе механизма унификации можно построить очень сильную и умную экспертную систему. При этом используя естественный язык как входной, так и выходной.
|