ОИИ_практикум_Пролог

ПАВЛОДАрский государственный
педагогический ИНСТИТУТ



КАБЕНОВ Д.И.


Практикум решения задач
по курсу «Основы искусственного интеллекта»

учебно-методическое пособие
для студентов, обучающихся по специальности «Информатика»



ПАВЛОДАр 2014
Рассматриваются типовые задачи и контрольные задания по курсу «Основы искусственного интеллекта». Пособие может быть использовано при организации самостоятельной работы студентов по выполнению заданий в среде Visual Prolog



Учебно-методическое пособие предназначено для студентов, обучающихся по специальности «информатика», а также может использоваться всеми, кто интересуется вопросами логического программирования.

ОГЛАВЛЕНИЕ
Введение...4
1. Основы ПРОЛОГа.5
1.1. Cреда Visual Prolog: основные понятия, интерфейс.5
1.2 Набор, редактирование и тестирование простейших программ в режиме Test Goal.7
1.3 Создание простейших проектов.13
1.4 Поиск с возвратом17
1.5 Управление поиском с возвратом: предикаты fail и отсечения ...20
1.6 Арифметические вычисления.25
1.7 Рекурсия28
1.8 Решение логических задач в ПРОЛОГе.32
1.9 Списки...36
2. Разработка графического интерфейса пользователя.....41
2.1 Создание простейших проектов с графическим интерфейсом.......41
2.2 Создание новых окон в проекте с использованием кнопок и полей ввода.45
2.3 Использование элемента ListBox..51
3. Создание экспертных систем средствами ПРОЛОГа...54
Литература......61
Введение

Предлагаемое методическое пособие представляет собой описание лабораторных работ по курсу «Основы искусственного интеллекта» и предназначено для студентов, обучающихся по специальности «Информатика».
Основная цель пособия – помощь студентам в подготовке к выполнению лабораторных работ.
Целью выполнения данных лабораторных работ является приобретение студентами навыков работы в среде Visual Prolog (формальная постановка задачи, преобразование в форму, пригодную для программирования на Прологе, трассировка и оценка результатов) а также закрепление теоретических знаний, полученных при прослушивании курса лекций «Основы искусственного интеллекта».
Пособие содержит необходимый теоретический материал, примеры решения задач и задания по программированию на языке Пролог.
К каждому разделу приводятся несколько типовых задач с решениями, что позволяет студентам самостоятельно подготовиться к выполнению лабораторной работы.
В качестве результата выполнения лабораторной работы студентом должен быть подготовлен отчет о проделанной работе, который включает:
Постановку задачи
Входные/Выходные данные (при необходимости)
Текст программы на языке Пролог (с необходимыми комментариями)
Трассировку программы
Результаты тестирования (наборы входных и выходных данных).
В настоящем пособии приводится список литературы, которая может быть использована при подготовке к лабораторным работам.

1. Основы ПРОЛОГа
1.1. Cреда Visual Prolog: основные понятия, интерфейс.
Prolog является языком, основанным на программировании логики (PROgramming in LOGic). Вместо детальных инструкций, предписывающих как решать ту или иную задачу, программист на языке Prolog уделяет основное внимание описанию задачи.
В среде Visual Prolog используется подход, получивший название «визуальное программирование», при котором внешний вид и поведение программ определяются с помощью специальных графических средств проектирования без традиционного программирования на алгоритмическом языке.
Visual Prolog автоматизирует построение сложных процедур и освобождает программиста от выполнения тривиальных операций. С помощью Visual Prolog проектирование пользовательского интерфейса и связанных- с ним окон, диалогов, меню, линии уведомлений о состояниях и т.д. производится в графической среде. С созданными объектами сразу же могут работать различные Кодовые Эксперты (Code Experts), которые используются для генерации базового и расширенного кодов на языке Prolog, необходимых для обеспечения их функционирования.
В Visual Prolog входят интерактивная среда визуальной разработки (VDE Visual Develop Environment), которая включает текстовый и различные графические редакторы, инструментальные средства генерации кода, конструирующие управляющую логику (Experts), а также являющийся расширением языка интерфейс визуального программирования (VPI Visual Programming Interface), Пролог-компилятор, набор различных подключаемых файлов и библиотек, редактор связей, файлы, содержащие примеры и помощь.
Visual Prolog поддерживается различными ОС, в том числе MS-DOS PharLap-Extended DOS, всеми версиями Windows, 16- и 32-битовыми целевыми платформами OS/2, а также некоторыми другими системами, требующими графического пользовательского интерфейса.
В зависимости от выбранного интерфейса разработчику обеспечивается доступ к множеству генераторов кода (Code Expert), всевозможным ресурсным редакторам и особым дополнительным VPI-предикатам, определениям и библиотекам. Ресурсные редакторы применяются для создания, компоновки и редактирования окон, диалогов, меню, панелей инструментов, строк помощи, строковых таблиц, ярлыков, курсоров, битовых карт и оперативной помощи. Генераторы кода на основе подобных структур создают необходимый первичный Prolog-код. В результате появляется первичный код («скелет»), готовый для компиляции, редактирования связей и выполнения.
Интерфейс Visual Prolog включает: главное меню, панель инструментов, окно проекта. Если во время последнего использования системы Visual Prolog там был открытый проект, то система автоматически вновь откроет этот проект.
На рис.1 изображен внешний вид среды Visual Prolog после запуска. В окне проекта отображаются модули открытого проекта route.prj: karta.pro, route.pro, VPITools.pro.


рис.1. Среда разработки Visual Prolog 6.1

Левая панель кнопок в окне проекта позволяет выбирать нужный компонент проекта: модуль, окно, меню и т.д. С помощью кнопок правой панели выбранный компонент можно редактировать(кнопка Edit), удалять(кнопка Delete), а также добавлять новый(кнопка New).
Пункт меню File содержит команды для работы с файлами. Чтобы создавать новое окно редактирования, можно использовать команду File | New. Эта команда создаст новое окно редактора с заголовком "NONAME".
В меню Edit представлены команды, позволяющие редактировать текст программы. Встроенный редактор системы по интерфейсу похож на обычный текстовый редактор. Можно производить вырезку, копирование и вставку текста, операции Отмена/Восстановление, которые можно активизировать из меню Edit. Также меню Edit показывает "горячие клавиши", связанные для этих действий.
Пункт меню Project содержит команды для работы с проектом: создать новый, открыть, запустить и т.д. Запуск проекта на исполнение выполняется нажатием кнопки на панели инструментов (или F9, или с помощью команд меню Project | Run).
Команды меню Options позволяют выполнять настройку проекта, устанавливать необходимые параметры.
ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
Запустите среду Visual Prolog. Откройте проект, указанный преподавателем. Запустите его на исполнение и проверьте его работу.
1.2 Набор, редактирование и тестирование простейших программ в режиме Test Goal
Программа на ПРОЛОГе состоит из предложений, которые могут быть фактами, правилами или запросами. Как правило, программа состоит из четырех разделов.
DOMAINS – секция описания доменов(типов). Секция применяется, если в программе используются нестандартные домены.
PREDICATES – секция описания предикатов. Секция применяется, если в программе используются нестандартные предикаты.
CLAUSES – секция предложений. Именно в этой секции записываются предложения: факты и правила вывода.
GOAL – секция цели. В этой секции записывается запрос.
Среда Visual Prolog позволяет протестировать программу без создания проекта. Для этого используется утилита Test Goal. Достаточно создать новый файл, набрать текст программы и активизировать Test Goal нажатием кнопки на панели инструментов. Автономно исполняемый файл при этом не создается. Утилита Test Goal компилирует только тот код, который определен в активном окне редактора (код в других открытых окнах или модулях проектов, если они есть, игнорируются). Test Goal находит все возможные решения задачи и автоматически выводит значения всех переменных.

Пример 1.
Имеется база данных, содержащая следующие факты:
родитель(илья, марина).
родитель(марина, ира).
родитель(елена, иван).
родитель(николай, ира).
родитель(ольга, алексей).
родитель(марина, саша).
родитель(сергей, иван).
Определить:
верно ли, что Марина является родителем Саши;
верно ли, что Алексей является родителем Ольги;
кто является ребенком Николая;
кто родители Ивана;
всех родителей и их детей.
Решение.
1. Запустите среду Visual Prolog. Закройте окно проекта (если оно открыто) и откройте новый файл (File|New) (рис.2)
В появившемся окне наберите текст программы, содержащий разделы: PREDICATES (описание предиката родитель), CLAUSES (перечисляются имеющиеся факты) и GOAL (запрос).

рис.2. Рабочее окно редактора
DOMAINS
имя=string
PREDICATES
nondeterm родитель(имя, имя)
CLAUSES
родитель(илья, марина).
родитель(марина, ира).
родитель(елена, иван).
родитель(николай, ира).
родитель(ольга, алексей).
родитель(марина, саша).
родитель(сергей, иван).
GOAL
родитель(марина, саша) .

Запустите и протестируйте программу с помощью команды Project | Test Goal (можно использовать кнопку на панели инструментов или сочетание клавиш +). Результат выполнения программы будет выведен в отдельном окне

рис3. Окно вывода результата

Указание: перед следующим запуском программы следует закрыть это окно.

2. Для ответа на вопрос: верно ли, что Алексей является родителем Ольги, измените запрос:
GOAL
родитель(алексей, ольга).
После запуска программы (Project | Test Goal) будет получен ответ:
no
3. Для ответа на вопрос: кто является ребенком Николая, запишите цель:
GOAL
родитель(николай, X).

Результат:
X=ира
1 Solution

4. Для ответа на вопрос: кто родители Ивана, укажите запрос:
GOAL
родитель(X, иван), родитель(Y, иван), X<>Y.

Результат:
X=елена, Y=сергей
X=сергей, Y=елена
2 Solutions

5. Для определения всех родителей и их детей, запишите:
GOAL
родитель(X, Y).

Результат:
X=илья, Y=марина
X=марина, Y=ира
X=елена, Y=иван
X=николай, Y=ира
X=ольга, Y=алексей
X=марина, Y=саша
X=сергей, Y=иван
7 Solutions

Пример 2
Имеются факты вида: родитель(имя, имя) и женщина(имя).
а) составить правило мать и определить, кто мать Маши.

Решение:
DOMAINS
имя=string
PREDICATES
родитель(имя, имя)
женщина(имя)
мать(имя,имя)
CLAUSES
родитель("Марина","Ирина").
родитель("Елена", "Анна").
родитель("Ольга","Марина").
родитель("Ольга","Татьяна").
родитель("Татьяна","Катя").
родитель("Анна", "Маша").
женщина("Ольга").
женщина("Маша").
женщина("Ирина").
женщина("Елена").
женщина("Анна").
женщина("Марина").
женщина("Татьяна ").
женщина("Катя").
мать(X,Y):-родитель(X,Y),женщина(X).
GOAL
мать(X,"Маша").

Результат:
X=Анна
1 Solution

b) составить правило бабушка и определить, кто бабушка Маши.
Решение:
DOMAINS
имя=string
PREDICATES
nondeterm родитель(имя,имя)
женщина(имя)
nondeterm мать(имя,имя)
nondeterm бабушка(имя,имя)
CLAUSES
родитель("Марина","Ирина").
родитель ("Елена", "Анна").
родитель("Ольга","Марина").
родитель("Ольга","Татьяна").
родитель("Татьяна","Катя").
родитель ("Анна", "Маша").
женщина("Ольга").
женщина( "Маша").
женщина("Ирина").
женщина("Елена").
женщина("Анна").
женщина("Марина").
женщина("Татьяна ").
женщина("Катя").
мать(X,Y):-родитель(X,Y),женщина(X).
бабушка(X,Z):-мать(X,Y),родитель(Y,Z).
GOAL
бабушка(X,"Маша").
Результат:
X=Елена
1 Solution

Замечание: ключевое слово nondeterm определяет недетерминированные предикаты, которые могут совершать откат назад и генерировать множественные решения. Таким образом, если задача предполагает возможность получения несколько решений, следует объявлять предикаты как недетерминированные.

c) составить правило внучка и определить, сколько внучек у Ольги и как их зовут.
Решение:
DOMAINS
имя=string
PREDICATES
nondeterm родитель(имя,имя)
женщина(имя)
nondeterm мать(имя,имя)
nondeterm бабушка(имя,имя)
nondeterm внучка(имя,имя)
CLAUSES
родитель("Марина","Ирина").
родитель ("Елена", "Анна").
родитель("Ольга","Марина").
родитель("Ольга","Татьяна").
родитель("Татьяна","Катя").
родитель("Анна", "Маша").
женщина("Ольга").
женщина( "Маша").
женщина("Ирина").
женщина("Елена").
женщина("Анна").
женщина("Марина").
женщина("Татьяна ").
женщина("Катя").
мать(X,Y):-родитель(X,Y),женщина(X).
бабушка(X,Z):-мать(X,Y),родитель(Y,Z).
внучка(X,Y):-бабушка(Y,X),женщина(X).
GOAL
внучка(X, "Ольга").

Результат:
X=Ирина
X=Катя
2 Solutions
ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
1. Имеется база данных, содержащая следующие факты:
любит(“Aнна,” яблоки).
любит(“Сергей”, бананы).
любит(“Андрей”, яблоки).
любит(“Света”, шоколад).
любит(“Вова”, шоколад).
любит(“Анна”, шоколад).
любит(“Света”, апельсины).
любит(“Вова”, бананы).
Составить программу, определяющую:
всех, кто любит бананы;
кто любит и шоколад, и яблоки;
что любит Вова;
что любят и Света, и Вова.
2. Имеется база данных, содержащая следующие факты:
играет (“Саша”, футбол).
играет (“Катя”, теннис).
играет (“Саша”, теннис).
играет (“Андрей”, футбол).
играет (“Олег”, футбол).
играет (“Ольга”, теннис).
играет (“Катя”, волейбол).
играет (“Олег”, волейбол).
Составить программу, определяющую:
каким видом спорта увлекается Андрей;
всех, кто играет в волейбол;
каким видом спорта увлекаются и Ольга, и Саша;
кто увлекается и футболом, и волейболом.
3. Имеется база данных, содержащая следующие факты:
любит(“Aнна,” яблоки).
любит(“Сергей”, бананы).
любит(“Андрей”, яблоки).
любит(“Света”, шоколад).
любит(“Вова”, шоколад).
любит(“Анна”, шоколад).
любит(“Света”, апельсины).
любит(“Вова”, бананы).
фрукты(яблоки ).
фрукты(бананы).
фрукты(апельсины ).
конфеты(шоколад).
используя имеющиеся факты, составить новое правило люб_фрукты(Х) и определить всех, кто любит фрукты;
используя имеющиеся факты, составить новое правило люб_конфеты(Х) и определить всех, кто любит конфеты;
используя имеющиеся факты, составить правило люб_вкусное(Х) и определить всех, кто любит и фрукты, и конфеты.
4. Имеется база данных, содержащая следующие факты:
играет (“Саша”, футбол).
играет (“Катя”, теннис).
играет (“Саша”, теннис).
играет (“Андрей”, футбол).
играет (“Олег”, футбол).
играет (“Ольга”, теннис).
играет (“Катя”, волейбол).
играет (“Олег”, волейбол).
женщина(“Катя”).
женщина(“Ольга”).
мужчина(“Саша”).
мужчина(“Андрей”).
мужчина(“Олег”).
используя имеющиеся факты, составить новое правило волейбол_жен(Х) и определить всех женщин, играющих в волейбол;
используя имеющиеся факты, составить новое правило футбол_муж(Х) и определить всех мужчин, играющих в футбол;
используя имеющиеся факты, составить правило теннис_пара(Х,Y), позволяющее найти смешанную теннисную пару (мужчина+женщина). Определить все такие пары.

Отчет о выполненной самостоятельной работе должен содержать:
тему лабораторной работы;
условие задачи;
листинг программы;
результаты ее тестирования.
1.3 Создание простейших проектов
Создание проекта позволяет протестировать пример как автономную исполняемую программу. После запуска проекта на исполнение создается exe-файл, работа которого завершается после первого решения, удовлетворяющего решению задачи. Запуск программы в этом режиме не обеспечивает автоматический вывод значений переменных, поэтому необходимо использовать стандартный предикат вывода write.

Пример.
Заданы отношения-факты:
родитель(“Иван”,”Катя”).
родитель(“Анна”,” Олег ”).
родитель(“Олег”,”Дима”).
родитель(“Игорь”,”Ольга”).
родитель(“Олег”,”Виктор”).
родитель(“Игорь”,”Иван”).
мужчина(“Дима”).
мужчина(“Иван”).
мужчина(“Игорь”).
мужчина(“Олег”).
мужчина(“Виктор”).
женщина(“Катя”).
женщина(“Ольга”).
женщина(“Анна”).
Составить новое отношение-правило дед(X,Y) и определить, кто является дедушкой Кати. Создать проект и протестировать пример как автономную исполняемую программу.

Решение
1. Запустите среду Visual Prolog и создайте новый проект (Project | New Project), активизируется окно Application Expert (эксперт приложения).
2. Определите имя проекта (Primer) и базовый каталог, куда будет сохранен проект (например, D:\VP\Primer)


рис.4. Окно Application Expert

На вкладке Target установите параметры и нажмите кнопку Create для создания проекта (рис. 5):

рис.5. Установки на вкладке Target окна Application Expert

3. Откройте окно Compiler Options (Options | Project | Compiler Options), откройте вкладку Warnings и установите опции компилятора для созданного проекта (рис.6):

рис.6. Установки опций компилятора
Нажмите OK.
4. В окне проекта выделите файл Primer.pro и откройте его для редактирования (двойной щелчок или кнопка Edit)


рис.7. Окно проекта
Файл с расширением .pro содержит секции PREDICATES, GOAL, CLAUSES. Допишите необходимые определения так, чтобы получилась программа:
DOMAINS
имя=string
PREDICATES
родитель(имя,имя)
женщина(имя)
мужчина(имя)
дед(имя, имя)
CLAUSES
родитель("Иван","Катя").
родитель("Анна","Олег").
родитель("Олег","Дима").
родитель("Игорь","Ольга").
родитель("Олег","Виктор").
родитель("Игорь","Иван").
мужчина("Дима").
мужчина("Иван").
мужчина("Игорь").
мужчина("Олег").
мужчина("Виктор").
женщина("Катя").
женщина("Ольга").
женщина("Анна").
дед(X,Z):-родитель(X,Y), родитель(Y,Z),
мужчина(X).
GOAL
дед(X,"Катя"),write(X).
5. Откомпилируйте исходный код примера и запустите его как автономную исполняемую программу. ( Project | Run, или клавиша , или кнопка ). Результат выполнения программы должен отобразиться в окне:


рис.8. Окно вывода результата
ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
Доработайте исходный код примера следующим образом:
1) добавьте новое правило бабушка и определите, кто является бабушкой;
2) добавьте новое правило внук и определите, кто внук Анны;
3) добавьте новое правило брат и определите, кто брат Димы;
4) добавьте новое правило сестра и определите, кто сестра Ивана.
Отчет о выполненной самостоятельной работе должен содержать:
тему лабораторной работы;
условие задачи;
полный окончательный код примера;
результаты ее тестирования.
1.4 Поиск с возвратом
Поиск с возвратом (backtracking) – это один из основных приемов поиска решений поставленной задачи в ПРОЛОГ’е. Выполняя поиск, ПРОЛОГ может столкнуться с необходимостью выбора между альтернативными путями. Тогда он ставит маркер у места развилки (точка отката) и выбирает первую подцель. Если она не выполняется, то ПРОЛОГ возвращается в точку отката и переходит к следующей подцели.
Среда Visual Prolog позволяет использовать отладчик для пошагового выполнения программы. Отладчик работает с откомпилированным кодом. В исходном коде можно ставить точки останова и выполнять программу по шагам. В режиме пошагового выполнения программы можно просматривать значения переменных и содержимое утвержденных фактов.

Пример
Имеется база данных, содержащая факты вида отдыхает(имя, город), украина(город), россия(город), прибалтика(город). Составить правило, позволяющее определить, кто отдыхал в России.
Проследить поиск решения задачи с помощью отладчика Visual Prolog и построить целевое дерево поиска с возвратом.
Решение:
1. Создайте новый проект (Project | New Project) и наберите текст программы:
DOMAINS
имя, город=string
PREDICATES
отдыхает(имя, город)
украина(город).
россия(город).
прибалтика(город).
отдых_Россия(имя)
CLAUSES
отдыхает(sasha, antalia).
отдыхает(anna, sochi).
отдыхает(dima, urmala).
отдыхает(oleg, kiev).
украина(kiev).
россия(sochi).
прибалтика(urmala).
отдых_Россия(X):-
отдыхает(X,Y),
россия(Y).
GOAL
отдых_Россия(X),
write(X),nl.

3. Сохраните проект (Project | Save Project)

4. Запустите его на исполнение ( Project | Run, или клавиша , или кнопка ). Результат выполнения программы:
anna

5. Проследите поиск этого решения с помощью отладчика(Debugger). Для этого:
а) запустите отладчик (Project | Debug);
б) в окне отладчика выберите команду View | Local Variables (для просмотра текущих значений переменных);
в) нажимайте клавишу (или Run | Trace Into) для пошагового выполнения программы, текущие значения переменных отображаются в окне Variables For Current Clause



рис.9. Окно отладчика
Поиск решения можно представить следующим образом:
13 SHAPE \* MERGEFORMAT 1415
рис.10. Целевое дерево поиска решения
ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
1. База данных содержит следующие факты:
увлекается(“Коля”, гитара).
увлекается(“Оля”, скрипка).
увлекается(“Дима”, плаванье).
увлекается(“Таня”, теннис).
спорт(плаванье).
спорт(теннис).
муз_инстр(скрипка).
муз_инстр(гитара).
а) составить правило спортсмен и определить, кто увлекается спортом;
б) проследить за поиском решения с помощью отладчика;
в) построить целевое дерево поиска с возвратом.

2. База данных содержит следующие факты:
увлекается(“Дима”, плаванье).
увлекается(“Таня”, теннис).
увлекается(“Коля”, гитара).
увлекается(“Оля”, скрипка).
спорт(плаванье).
спорт(теннис).
муз_инстр(скрипка).
муз_инстр(гитара).
а) составить правило музыкант и определить, кто увлекается музыкой;
б) проследить за поиском решения с помощью отладчика;
в) построить целевое дерево поиска с возвратом.
Отчет о выполненной самостоятельной работе должен содержать:
тему лабораторной работы;
условие задачи;
листинг программы;
результаты ее тестирования;
целевое дерево поиска решения.
1.5 Управление поиском с возвратом: предикаты fail и отсечения.
fail – это тождественно-ложный предикат, искусственно создающий ситуацию неуспеха. После выполнения этого предиката управление передается в точку отката и поиск продолжается. Использование предиката fail позволяет найти все решения задачи.
Чтобы ограничить пространство поиска и прервать поиск решений при выполнении какого-либо условия, используется предикат отсечения (обозначается !), Однажды пройдя через отсечение, невозможно вернуться назад, т.к. этот предикат является тождественно-истинным. Процесс может только перейти к следующей подцели, если такая имеется.
Например, p :- p1, p2, !, p3.
Если достигнуты цели p1 и p2, то возврат к ним для поиска новых решений невозможен.

Пример 1
База данных содержит факты вида: student(имя, курс). Создать проект, позволяющий сформировать список студентов 1-го курса.
Решение:
PREDICATES
student(symbol,integer)
spisok
CLAUSES
student(vova,3).
student(lena,1).
student(dima,1).
student(ira,2).
student(marina,1).
spisok:-student(X,1),write(X),nl,fail.
GOAL
write("Список студентов 1-курса"),nl,spisok.

Результат выполнения программы:
Список студентов 1-курса
lena
dima
marina
Пример 2
База данных содержит факты вида father(name, name). Создать проект, позволяющий определить кто чей отец.
Решение:
DOMAINS
name=symbol
PREDICATES
father (name, name)
everybody
CLAUSES
father ("Павел", "Петр").
father ("Петр", "Михаил").
father ("Петр", "Иван").
everybody:- father (X, Y),
write(X," - это отец",Y,"а"),nl,
fail.
GOAL
everybody.

Результат выполнения программы:
Павел - это отец Петра
Петр - это отец Михаила
Петр - это отец Ивана

Пример 3
Создать проект, реализующий железнодорожный справочник. В справочнике содержится следующая информация о каждом поезде: номер поезда, пункт назначения и время отправления.
а) вывести всю информацию из справочника.
Решение:
DOMAINS
nom=integer
p, t=string
PREDICATES
poezd(nom,p,t)
CLAUSES
poezd(233,moskva,"12-30").
poezd(257,moskva,"22-40").
poezd(133,armavir,"10-20").
poezd(353,armavir,"20-40").
poezd(353,adler,"02-30").
poezd(413,adler,"11-10").
poezd(256,piter,"21-30").
GOAL
write(" Расписание поездов"), nl,
write("Номер Пункт прибытия Время отправления"),
nl, poezd(N,P,T), write(N," ",P," ",T),nl,fail.
Результат выполнения программы
Расписание поездов
Номер Пункт прибытия Время отправления
233 moskva 12-30
257 moskva 22-40
133 armavir 10-20
353 armavir 20-40
353 adler 02-30
413 adler 11-10
256 piter 21-30

б) организовать поиск поезда по пункту назначения.
Решение:
GOAL
write (" Пункт назначения:"), Readln(P), nl,
write ("Номер Время отправления"), nl,
poezd(N,P,T), write(N," ",T), nl, fail.

Комментарий: Readln –стандартный предикат ввода строкового значения

Результат выполнения программы
Пункт назначения:armavir

Номер Время отправления
133 10-20
353 20-40
в) вывести информацию о поездах, отправляющихся в заданный временной промежуток
Решение:
GOAL
write(" Время отправления:"),nl,
write("c..."), Readln(T1),
write("до..."), Readln(T2), nl,
write("Номер Пункт назначения Время отправления"),
nl,poezd(N,P,T),T>=T1,T<=T2,write(N," ",P," ", T),
nl, fail.

Результат выполнения программы
Время отправления:
c...10-00
до...15-00

Номер Пункт назначения Время отправления
233 moskva 12-30
133 armavir 10-20
413 adler 11-10
Пример 4
Имеется база данных, содержащая данные о спортсменах: имя и вид спорта. Определить возможные пары одного из спортсменов-теннисистов с другими теннисистами.
Решение:
DOMAINS
имя,вид_сп=string
PREDICATES
играет(имя,вид_сп)
спис_спортс
CLAUSES
играет("Саша",теннис).
играет("Аня",волейбол).
играет("Олег",футбол).
играет("Коля",теннис).
играет("Саша",футбол).
играет("Андрей",теннис).
спис_спортс:- играет(X,теннис),!,играет(Y,теннис),
X<>Y,write(X,"-",Y),nl,fail.
GOAL
write("Пары теннисистов"),nl,
спис_спортс.

Результат выполнения программы:
Пары теннисистов
Саша-Коля
Саша-Андрей

Пример 5
Студенту в зависимости от набранной в процессе обучения суммы баллов Z присваивается квалификация:
магистр (М), если 80<=Z<=100
специалист (S), если 60<= Z< 80
бакалавр (B), если 40<= Z< 60
неудачник (N), если 0<=Z< 40
Составить программу, которая определит квалификацию в зависимости от введенного значения Z
Решение:
Для решения задачи составим правило grade, устанавливающее связь между количеством баллов (z) и квалификацией (r). Правило состоит из нескольких частей. Первые две части обеспечивают проверку недопустимых значений Z с выводом соответствующего сообщения. Остальные части правила определяют квалификацию в зависимости от значения Z.
DOMAINS
z=integer
r=string
PREDICATES
grade(z,r)
CLAUSES
grade(Z,""):-Z<0,!, write("Неверный ввод данных!").
grade(Z,""):-Z>100,!,write("Неверный ввод данных!").
grade(Z,"M"):-Z>=80,!.
grade(Z,"S"):-Z>=60,!.
grade(Z,"B"):-Z>=40,!.
grade(Z,"N").
GOAL
write("Z="), readint(Z), grade(Z,R),write(R).

Комментарий: readint – стандартный предикат ввода целочисленного значения

Результат выполнения программы:
1-й случай:
Z=88
M
2-й случай:
Z=65
S
3-й случай:
Z=39
N
4-й случай:
Z=110
Неверный ввод данных!
ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
1. База данных содержит факты вида: отдыхает(имя, город), украина(город), россия(город), женщина (имя), мужчина(имя ).
а) вывести список женщин, отдыхающих в России;
б) вывести список мужчин, отдыхающих на Украине.
2. База данных содержит факты вида: книга(автор, название, издательство, год_издания), украина(город).
а) вывести весь список книг;
б) вывести список книг авторов Пушкина и Чехова;
в) вывести список книг, изданных в издательстве «Питер» не ранее 2000 года.
3. Составить программу, реализующую авиасправочник. В справочнике содержится следующая информация о каждом рейсе: номер рейса, пункт назначения, время вылета, дни(ежедн., чет, нечет). Вывести:
а) всю информацию из справочника;
б) информацию о самолетах, вылетающих в заданный пункт по четным дням;
в) информацию о самолетах, вылетающих ежедневно не позже указанного времени.
4. Составить программу, реализующую географический справочник. В справочнике содержится следующая информация о каждой стране: название страны, название столицы, численность населения, географическое положение (Европа или Азия ). Вывести:
а) всю информацию из справочника;
б) информацию о странах, численность населения которых превышает заданное значение;
в) информацию о европейских странах, численность населения которых не превышает заданное значение.
5. Составить программу, реализующую словарь. В словаре содержится следующая информация: слово и его перевод (русские и английские слова). Реализовать вывод всего словаря, перевод с русского на английский, с английского на русский (с несколькими значениями).
6. Составить программу, реализующую телефонный справочник. В справочнике содержится следующая информация о каждом абоненте: имя и телефон. Реализовать вывод всей информации из справочника, поиск телефона по имени, поиск имени по телефону
7. База данных содержит факты вида: ученик(имя, класс) и увлекается(имя, хобби). Составить программу, которая выводит:
а) список всех учеников и их увлечения;
б) подбирает одному из учеников указанного класса, увлекающемуся кино, пару из других классов. Вывести все возможные пары.
8. База данных содержит факты вида: ученик(имя, класс) и играет(имя, вид_спорта). Составить программу, которая:
а) выводит список всех учеников заданного класса и вид спорта, которым они увлекаются;
б) подбирает одному из учеников указанного класса, играющему в бадминтон, пару из других классов. Вывести все возможные пары.

Отчет о выполненной самостоятельной работе должен содержать:
тему лабораторной работы;
условие задачи;
листинг программы;
результаты ее тестирования с различными исходными данными.
1.6 Арифметические вычисления
Хотя Пролог не предназначен для решения вычислительных задач, его возможности вычислений аналогичны соответствующим возможностям таких языков программирования как Basic, C, Pascal.
В языке Пролог имеется ряд встроенных функций для вычисления арифметических выражений, некоторые из которых перечислены в таблице 1.
Таблица 1. Математические операции и функции в Прологе
X + Y
Сумма X и Y

X – Y
Разность X и Y

X * Y
Произведение X и Y

X / Y
Деление X на Y

X mod Y
Остаток от деления X на Y

X div Y
Целочисленное деление X на Y

abs(X)
Абсолютная величина числа X

sqrt(X)
Квадратный корень из X

random(X)
Случайное число в диапазоне от 0 до 1

random(Int,X)
Случайное целое число в диапазоне от 0 до Int

round(X)
Округление Х

trunc(X)
Целая часть Х

sin(X)
Синус X

cos(X)
Косинус X

arctan(X)
Арктангенс Х

tan(X)
Тангенс X

ln(X)
Натуральный логарифм X

log(X)
Логарифм Х по основанию 10


Пример 1.
Вычислить значение выражения Z=(2*X+Y)/(X-Y) для введенных X и Y.
Решение:
PREDICATES
знач_выраж(real,real)
CLAUSES
знач_выраж(X,Y):-X<>Y, Z=(2*X+Y)/(X-Y),
write("Z=",Z);
write ("Делить на 0 нельзя!").
GOAL
Write("X="),readreal(X),
Write("Y="),readreal(Y),знач_выраж(X,Y),nl.

Комментарий: readreal – предикат для ввода действительных чисел

Результат выполнения программы:
1-й случай:
X=4
Y=4
Делить на 0 нельзя!
2-й случай:
X=5
Y=2
Z=4
Пример 2.
Найти минимальное из двух введенных A и B.
Решение:
PREDICATES
min(integer,integer,integer)
CLAUSES
min(A,B,A):-A<=B,!.
min(A,B,B).
GOAL
Write("A="),readreal(A),Write("B="),readreal(B),
min(A,B,Min),write("min=",Min),nl.

Результат выполнения программы:
1-й случай:
A=5
B=17
min=5
2-й случай:
A=35
B=18
min=18
3-й случай:
A=8
B=8
min=8

Пример 3.
Определить, является четным или нечетным случайным образом выбранное число от 0 до 20.
Решение:
PREDICATES
chet
CLAUSES
chet:-random(20,X),write(X),X mod 2=0,
write(" - четное"),!.
chet:-write( " - нечетное").
GOAL
chet.

Результат выполнения программы:
1-й случай:
6 – четное
2-й случай:
19 – нечетное
ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
Составить программу для вычисления значения выражения Y=(X2+1)/(X-2) для введенного X.
Составить программу для вычисления значения выражения S=2(X2+Y2)/(X+Y) для введенных X и Y.
Составить программу для вычисления значения выражения z=exsinx +3lnx для введенного X.
Составить программу для вычисления значения выражения y=ln(lg(sinx+ex))для введенного X.
Составить программу для вычисления среднего арифметического двух введенных чисел.
Составить программу для вычисления среднего геометрического двух введенных чисел.
Составить программу для проверки введенного натурального числа на четность.
Составить программу для проверки попадает ли введенное число X в заданный промежуток [a,b].
Составить программу для выбора наименьшего из трех введенных чисел.
Составить программу для выбора наибольшего из трех введенных чисел.

Отчет о выполненной самостоятельной работе должен содержать:
тему лабораторной работы;
условие задачи;
листинг программы;
результаты ее тестирования с различными исходными данными.
1.7 Рекурсия
Рекурсивная процедура – это процедура, вызывающая сама себя до тех пор, пока не будет соблюдено некоторое условие, которое остановит рекурсию. Такое условие называют граничным. Рекурсивное правило всегда состоит по крайней мере из двух частей, одна из которых является нерекурсивной. Она и определяет граничное условие.
В рекурсивной процедуре нет проблемы запоминания результатов ее выполнения, потому что любые вычисленные значения можно передавать из одного вызова в другой как аргументы рекурсивно вызываемого предиката. Рекурсия является эффективным способом для решения задач, содержащих в себе подзадачу такого же типа.

Пример 1.
База данных содержит следующие факты:
roditel(ivan,oleg).
roditel(inna,oleg).
roditel(oleg,dima).
roditel(oleg,marina).
Составить рекурсивное правило предок и определить всех предков и их потомков.
Решение:
DOMAINS
name=string
PREDICATES
roditel(name,name)
predok(name,name)
CLAUSES
roditel(ivan,oleg).
roditel(inna,oleg).
roditel(oleg,dima).
roditel(oleg,marina).
predok(X,Z):-roditel(X,Z). % нерекурсивная часть правила
predok(X,Z):-roditel(X,Y), % рекурсивная часть правила
predok(Y,Z).
GOAL
predok(X,Y),
write("Рredok -",X," Еgo potomok-",Y),nl,fail.

Результат выполнения программы:
Рredok -ivan Еgo potomok-oleg
Рredok -inna Еgo potomok-oleg
Рredok -oleg Еgo potomok-dima
Рredok -oleg Еgo potomok-marina
Рredok -ivan Еgo potomok-dima
Рredok -ivan Еgo potomok-marina
Рredok -inna Еgo potomok-dima
Рredok -inna Еgo potomok-marina

Пример 2. Вычисление факториала.
Решение:
PREDICATES
fact(integer,integer)
CLAUSES
fact(0,1):-!. % Факториал нуля равен единице
fact(N,F):- N1=N-1, % уменьшаем N на единицу,
fact(N1,F1), % вычисляем факториал нового числа,
F=N*F1. % а затем умножает его на N
GOAL
write("N="),readint(N),fact(N,F),write("F=",F),nl.

Результат выполнения программы:
1-й случай:
N=0
F=1
2-й случай:
N=1
F=1
3-й случай:
N=4
F=24

Пример 3
Составить программу для вычисления Y=Xn, X, n – целые числа
Решение:
Составим правило stepen, состоящее из 3-х частей.
1-я часть правила (нерекурсивная) определяет, что Х0=1.
2-я часть правила (рекурсивная) вычисляет Хn для положительного n.
3-я часть (рекурсивная) - вычисляет Хn для отрицательного n (добавляется необходимое условие Х<>0)

PREDICATES
stepen(real,real,real)
CLAUSES
stepen(X,0,1):-!.
stepen(X,N,Y):-N>0,N1=N-1,stepen(X,N1,Y1),Y=Y1*X,!.
stepen(X,N,Y):-X<>0,K=-N,stepen(X,K,Z),Y=1/Z.
GOAL
write("X="),readreal(X),
write("N="),readreal(N),
stepen(X,N,Y),write("Y=",Y),nl.

Результат выполнения программы:
1-й случай:
X=3
N=2
Y=9
2-й случай:
X=2
N=-2
Y=0.25

Пример 4 . Ханойские башни
Имеется три стержня: A, B и C. На стержне А надеты N дисков разного диаметра, надетые друг на друга в порядке убывания диаметров. Необходимо переместить диски со стержня А на стержень С используя В как вспомогательный, если перекладывать можно только по одному диску и нельзя больший диск класть на меньший.
Решение:
Составим правило move, определяющее порядок переноса дисков.
1-я (нерекурсивная) часть правила определяет действие, если на стержне находится 1 диск.
2-я (рекурсивная) часть правила перемещает сначала верхние N-1 диск на стержень B, используя С как вспомогательный, затем оставшийся диск на стержень C и, наконец, диски со стержня B на C, используя А как вспомогательный.
PREDICATES
move(integer,char,char,char)
CLAUSES
move(1,A,B,C):-
write("Перенести диск с ",A," на  ",C),nl,!.
move(N,A,B,C):-
M=N-1,move(M,A,C,B),
write("Перенести диск с ",A," на  ",C),nl,
move(M,B,A,C).
GOAL
write("Ханойские башни"), nl,
write("Количество дисков:"), readint(N),nl,
move(N,'A','B','C').

Результат выполнения программы:
Ханойские башни
Количество дисков:3

Перенести диск с A на C
Перенести диск с A на B
Перенести диск с C на B
Перенести диск с A на C
Перенести диск с B на A
Перенести диск с B на C
Перенести диск с A на C
ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
Вычислить сумму 1+2+3++N.
Подсчитать сумму ряда целых четных чисел от 2 до N.
Вычислить сумму ряда целых нечетных чисел от 1 до n.
Найти значение произведения: 2*4*6*...*26
Найти значение произведения: 1*3*5*...*11
Вычислить значение n-го члена ряда Фибоначчи: f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2).
Используя базу данных и правило предок из примера 2 составить правило для определения всех потомков-мужчин.
Используя базу данных и правило предок из примера 2 составить правило для определения всех потомков-женщин.
Отчет о выполненной самостоятельной работе должен содержать:
тему лабораторной работы;
условие задачи;
листинг программы;
результаты ее тестирования.
1.8 Решение логических задач в ПРОЛОГе
ПРОЛОГ позволяет наиболее естественным образом решать логические задачи, моделируя процесс размышления человека с помощью правил.
Многие логические задачи связаны с рассмотрением нескольких конечных множеств с одинаковым количеством элементов, между которыми устанавливается взаимно-однозначное соответствие. В ПРОЛОГе эти множества можно описывать как базы данных, а зависимости между объектами устанавливать с помощью правил.
Пример 1
В автомобильных гонках три первых места заняли Алеша, Петя и Коля. Какое место занял каждый из них, если Петя занял не второе и не третье место, а Коля - не третье?
Решение
Традиционным способом задача решается заполнением таблицы. По условию задачи Петя занял не второе и не третье место, а Коля - не третье. Это позволяет поставить символ '-' в соответствующих клетках.

Имя
I место
II место
III место

Алеша
 
 
 

Петя
 
-
-

Коля
 
 
-

Между множеством имен участников гонки и множеством мест должно быть установлено взаимнооднозначное соответствие. Поэтому определяем занятое место сначала у Пети, затем у Коли и, наконец, у Алеши. В соответствующих клетках проставляем знак '+'. В каждой строке и каждом столбце должен быть только один такой знак.

Имя
I место
II место
III место

Алеша
-
-
+

Петя
+
-
-

Коля
-
+
-

Из последней таблицы следует, что Алеша занял третье место, Петя - первое, Коля - второе.
Программа на ПРОЛОГе будет выглядеть следующим образом:
PREDICATES
имя(string)
место(string)
соответствие(string,string)
решение(string,string,string,string,string,string)
CLAUSES
имя(алеша).
имя(петя).
имя(коля).
место(первое).
место(второе).
место(третье).
/* Устанавливаем взаимнооднозначное соответствие
между множеством имен и множеством мест, X - имя,Y - место */
/* Петя занял не второе и не третье место */
соответствие(X, Y):-имя(X), X=петя,
место(Y),not(Y=второе),
not(Y=третье).
/* Коля занял не третье место */
соответствие(X, Y):- имя(X), X=коля,
место(Y), not(Y=третье).
соответствие(X, Y):- имя(X), X=алеша, место(Y).
/* У всех ребят разные места */
решение(X1,Y1,X2,Y2,X3,Y3):-
X1=петя,соответствие(X1,Y1),
X2=коля,соответствие(X2,Y2),
X3=алеша,соответствие(X3,Y3),
Y1<>Y2, Y2<>Y3, Y1<>Y3.
GOAL
решение(X1,Y1,X2,Y2,X3,Y3), write(X1," - ",Y1),nl,
write(X2," - ",Y2),nl,write(X3," - ",Y3),nl.

Результат выполнения программы
петя - первое
коля - второе
алеша - третье

Пример 2
Наташа, Валя и Аня вышли на прогулку, причем туфли и платье каждой были или белого, или синего, или зеленого цвета. У Наташи были зеленые туфли, а Валя не любит белый цвет. Только у Ани платье и туфли были одного цвета. Определить цвет туфель и платья каждой из девочек, если у всех туфли и платья были разного цвета.
Решение
PREDICATES
имя(string)
туфли(string)
платье(string)
соот(string,string,string)
решение(string,string,string,string,string,string,
string,string,string)
CLAUSES
имя(наташа).
имя(валя).
имя(аня).
туфли(белый).
туфли(синий).
туфли(зеленый).
платье(белый).
платье(синий).
платье(зеленый).
% X – имя, Y – цвет туфель, Z – цвет платья
соот(X,Y,Z):-имя(X),туфли(Y),платье(Z),
X=наташа,Y=зеленый,Y<>Z.
соот(X,Y,Z):-имя(X),туфли(Y),платье(Z),
X=валя,not(Y=белый),
not(Z=белый), Y<>Z.
соот(X,Y,Z):-имя(X),туфли(Y),платье(Z),X=аня,Y=Z.
решение(X1,Y1,Z1,X2,Y2,Z2,X3,Y3,Z3):-
X1=наташа,соот(X1,Y1,Z1),
X2=валя, соот(X2,Y2,Z2),
X3=аня, соот(X3,Y3,Z3),
Y1<>Y2, Y2<>Y3, Y1<>Y3,
Z1<>Z2, Z2<>Z3, Z1<>Z3.
GOAL
решение(X1,Y1,Z1,X2,Y2,Z2,X3,Y3,Z3),
write(X1," туфли- ",Y1," платье- ",Z1),nl,
write(X2," туфли- ",Y2," платье- ",Z2),nl,
write(X3," туфли- ",Y3," платье- ",Z3),nl.

Результат выполнения программы
наташа туфли - зеленый платье - синий
валя туфли - синий платье - зеленый
аня туфли - белый платье - белый

Пример 3
Витя, Юра и Миша сидели на скамейке. В каком порядке они сидели, если известно, что Миша сидел слева от Юры, а Витя слева от Миши.
Решение
PREDICATES
слева(string,string)
ряд(string,string,string)
CLAUSES
/* Миша сидел слева от Юры */
слева(миша, юра).
/* Витя сидел слева от Миши */
слева(витя, миша).
/* Объекты X, Y и Z образуют ряд,
если Х слева от Y и Y слева от Z */
ряд(X, Y, Z):- слева(X,Y), слева(Y, Z).
GOAL
ряд(X, Y, Z), write(X,"-",Y,"-",Z),nl.

Результат выполнения программы
витя-миша-юра

Пример 4
Известно, что тополь выше березы, которая выше липы. Клен ниже липы, а сосна выше тополя и ниже ели. Определить самое высокое и самое низкое дерево.
Решение
DOMAINS
name=string
PREDICATES
выше(name,name)
ряд(name,name,name,name,name,name)
CLAUSES
выше(тополь,береза).
выше(липа,клен).
выше(ель,сосна).
выше(береза,липа).
выше(сосна,тополь).
ряд(X1,X2,X3,X4,X5,X6):-выше(X1,X2),выше(X2,X3),
выше(X3,X4),выше(X4,X5),
выше(X5,X6).
GOAL
ряд(X,_,_,_,_,Y),write("Самое высокое - ",X),nl,
write("Самое низкое - ",Y),nl.

Результат выполнения программы
Самое высокое - ель
Самое низкое - клен
ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
1. Трое ребят вышли гулять с собакой, кошкой и хомячком. Известно, что Петя не любит кошек и живет в одном подъезде с хозяйкой хомячка. Лена дружит с Таней, гуляющей с кошкой. Определить, с каким животным гулял каждый из детей.
2. Беседуют трое друзей: Белокуров, Рыжов и Чернов. Брюнет сказал Белокурову: «Любопытно, что один из нас блондин, другой – брюнет, а третий – рыжий, но ни у кого цвет волос не соответствует фамилии». Какой цвет волос у каждого из друзей?
3. Витя, Юра, Миша и Дима сидели на скамейке. В каком порядке они сидели, если известно, что Юра сидел справа от Димы, Миша справа от Вити, а Витя справа от Юры.
4. Известно, что Волга длиннее Амударьи, а Днепр короче Амударьи. Лена длиннее Волги. Определить вторую по протяженности реку.
Отчет о выполненной самостоятельной работе должен содержать:
тему лабораторной работы;
условие задачи;
решение задачи традиционным способом (с помощью таблицы);
листинг программы;
результаты ее тестирования с различными исходными данными.
1.9 Списки
Список – это объект, который содержит конечное число других объектов. Список в ПРОЛОГе заключается в квадратные скобки и элементы списка разделяются запятыми. Список, который не содержит ни одного элемента, называется пустым списком.
Список является рекурсивным объектом. Он состоит из головы (первого элемента списка) и хвоста (все последующие элемента). Хвост также является списком. В ПРОЛОГе имеется операция “|”, которая позволяет делить список на голову и хвост. Пустой список нельзя разделить на голову и хвост.
Тип данных "список" объявляется в программе на Прологе следующим образом:
DOMAINS
списковый_тип = тип*
где "тип" - тип элементов списка; это может быть как стандартный тип, так и нестандартный, заданный пользователем и объявленный в разделе DOMAINS ранее.
Основными операциями на списками являются:
формирование списка;
объединение списков;
поиск элемента в списке;
вставка элемента в список и удаление из списка.

Пример 1
Сформировать список вида [7,6,5,4,3,2,1]
Решение
DOMAINS
list = integer*
PREDICATES
genl(integer, list)
CLAUSES
genl(0,[]):-!.
genl(N,[N|L]):-N1=N-1, genl(N1,L).
GOAL
genl(7,L),write(L),nl.

Результат выполнения программы:
[7,6,5,4,3,2,1]

Пример 2
Сформировать список из N элементов, начиная с 2. Каждый следующий на 4 больше предыдущего.
Решение
DOMAINS
list = integer*
PREDICATES
genl( integer, integer, list )
CLAUSES
genl(N2,N2,[]):-!.
genl(N1,N2,[N1|L]):-N1 genl(N,N2,L).
GOAL
write("N="),readint(N),K=4*(N+1)-2,
genl(2,K,L),write(L),nl.

Результат выполнения программы:
N=5
[2,6,10,14,18]

Пример 3
Сформировать список последовательных натуральных чисел от 4 до 20 и найти количество его элементов.
Решение:
DOMAINS
list = integer*
PREDICATES
genl1(integer, integer, list )
len(integer, list )
CLAUSES
genl1(N2,N2,[]):-!.
genl1(N1,N2,[N1|L]):-N1len(0,[]).
len(X,[_|L]):-len(X1,L), X=X1+1.
GOAL
genl1 (4,21,L ),write(L),nl,
len(X, L),write("Количество элементов=",X),nl.
Результат выполнения программы:
[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
Количество элементов=17

Пример 4
Определить, содержится ли введенное число Х в заданном списке L.
Решение:
DOMAINS
list = integer*
PREDICATES
member(integer, list)
CLAUSES
member(X,[X|_]):-write("yes"),!.
member(X,[]):-write("no"),!.
member(X,[_|L]) :- member(X, L).
GOAL
L=[1,2,3,4], write(L),nl, write("X="),readint(X),
member(X, L),nl.

Результат выполнения программы:
1-й случай:
[1,2,3,4]
X=3
yes
2-й случай:
[1,2,3,4]
X=5
no

Пример 5
Сформировать списки L1=[1,2,3], L2=[10,11,12,13,14,15] и объединить их в список L3.
Решение:
DOMAINS
list = integer*
PREDICATES
genl1(integer,integer,list)
append(list,list,list)
CLAUSES
genl1(N2,N2,[]):-!.
genl1(N1,N2,[N1|L]):-N1append([],L,L).
append([X|L1],L2,[X|L3]):-append(L1,L2,L3).
GOAL
genl1(1,4,L1),write("L1=",L1),nl,
genl1(10,16,L2),write("L2=",L2),nl,
append(L1,L2,L3),write("L3=",L3),nl.
Результат выполнения программы:
L1=[1,2,3]
L2=[10,11,12,13,14,15]
L3=[1,2,3,10,11,12,13,14,15]

Пример 6
Удалить из списка, элементами которого являются названия дней недели, указанный элемент.
Решение:
DOMAINS
list = symbol*
PREDICATES
del(symbol,list,list)
CLAUSES
del(X,[X|L],L).
del(X,[Y|L],[Y|L1]):-del(X,L,L1).
GOAL
L=[пн, вт, ср, чт, пт, сб, вс],write("L=",L),nl,
write("X="),readln(X),
del(X,L,L1),write("L1=",L1),!;
write("Элемент отсутствует в списке"),nl.

Результат выполнения программы:
1-й случай:
L=["пн","вт","ср","чт","пт","сб","вс"]
X=ср
L1=["пн","вт","чт","пт","сб","вс"]
2-й случай:
L=["пн","вт","ср","чт","пт","сб","вс"]
X=пр
Элемент отсутствует в списке

Пример 7
Вставить в список имен новый элемент, значение которого вводится с клавиатуры. Вывести все возможные варианты вставок.
Решение:
DOMAINS
list = symbol*
PREDICATES
del(symbol,list,list)
ins(symbol,list,list)
CLAUSES
del(X,[X|L],L).
del(X,[Y|L],[Y|L1]):-del(X,L,L1).
ins(X,L1,L):-del(X,L,L1).
GOAL
L=[olga, oksana, toma, dima],write("L=",L),nl,
write("X="),readln(X),
ins(X,L,L1),write("L1=",L1),nl, fail.

Результат выполнения программы:
L=["olga","oksana","toma","dima"]
X=vera
L1=["vera","olga","oksana","toma","dima"]
L1=["olga","vera","oksana","toma","dima"]
L1=["olga","oksana","vera","toma","dima"]
L1=["olga","oksana","toma","vera","dima"]
L1=["olga","oksana","toma","dima","vera"]

Пример 8
Найти сумму элементов списка целых чисел.
Решение:
DOMAINS
list=integer*
PREDICATES
sum_list(list, integer)
CLAUSES
sum_list([],0).
sum_list([X|L],S):-sum_list(L,S1),S=S1+X.
GOAL
L=[1,2,3,4,5],sum_list(L,S), write("S=",S).

Результат выполнения программы:
S=15
ЗАДАНИЯ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
Сформировать список [2, 4, 6, 8, 10] и удалить из него введенное число.
Сформировать списки [1, 3, 5, 7, 9] и [2, 4, 6, 8, 10] и объединить их в один.
Сформировать список [3, 6, 9, 12, 15, 18] и вставить в него введенное число.
Сформировать список из N натуральных чисел, начиная с 10. Каждое следующее на 5 больше предыдущего.
Сформировать список [3, 6, 9, 12, 15] и найти сумму его элементов
Сформировать список [6, 5, 4, 3, 2] и найти сумму его элементов
Сформировать список [7, 5, 3, 1] и найти произведение его элементов
Сформировать список из N последовательных натуральных чисел, начиная с 10. Найти сумму его элементов

Отчет о выполненной самостоятельной работе должен содержать:
тему лабораторной работы;
условие задачи;
листинг программы;
результаты ее тестирования.
2 Разработка графического интерфейса пользователя
2.1 Создание простейших проектов с графическим интерфейсом
Визуальное создание компонентов проводится в интерактивном режиме, после чего автоматически генерируется исполняемая программа. Все необходимые файлы проекта создает эксперт приложений. Использование выбранных программистом ресурсов графического интерфейса обеспечивает эксперт ресурсов. Причем, ресурсы могут быть импортированы из динамически связанных библиотек, приложений, файлов ресурсов и других проектов Visual Prolog.
При создании проекта с графическим интерфейсом Visual Prolog создает основу проекта, содержащую главное меню, панель инструментов и окно для вывода сообщений. Новое приложение может быть создано за достаточно короткий промежуток времени и затем последовательно расширено до конечного приложения

Пример. Проект, позволяющий ввести имя пользователя и вывести приветствие.
Задание: создать проект, содержащий пункт главного меню test, при выборе которого выводится диалоговое окно для ввода имени пользователя. После завершения ввода должно появиться приветственное сообщение.

Решение
1. Запустите среду Visual Prolog и создайте новый проект (Project | New Project), активизируется окно Application Expert (рис.11).
2. Определите имя проекта (например, MyProj) и базовый каталог, куда будет сохранен проект (например, D:\VP\ MyProj).

рис.11. Диалоговое окно Application Expert
Нажмите Create для создания проекта. Проект с графическим интерфейсом уже создан. Запустите его на выполнение (Project | Run, или клавиша , или кнопка ).


рис.12. Приложение по умолчанию
Проверьте, какие из пунктов главного меню реагируют на действия пользователя. Завершите работу приложения MyProj.
3. Проект по умолчанию – это основа для формирования собственного приложения. Доработайте проект, добавив новый пункт меню Test, при выборе которого должно появиться окно для ввода имени пользователя. После ввода имени должна появиться приветствующая надпись в окне Messages. Для этого выполните действия:
а) создание нового пункта меню: в окне проекта нажмите кнопку Menu на левой панели инструментов, а затем двойным щелчком активизируйте редактор меню (или нажмите Edit на правой панели инструментов)


рис.13. Окно проекта, показывающее зарегистрированное меню
В открывшемся окне выделите пункт меню Edit и нажатием кнопки New добавьте новый пункт меню (рис.14).







.
рис.14. Добавление пункта меню в редакторе меню
Введите название пункта меню &Test. Имя-константа для него будет присвоено автоматически
Нажмите ОК, а затем Close для закрытия окна Task Menu.
Сохраните сделанные в меню изменения
б) создание диалогового окна для ввода имени пользователя: в окне проекта нажмите кнопку Window на левой панели инструментов, а затем вызовите эксперт окон нажатием кнопки Code Expert . Откроется окно Dialog and Window Expert (рис.15)

рис.15. Эксперт окон и диалоговых окон создает код меню
Выберите пункт Menu в списке Event Type и выделите строку id_test (имя нового пункта меню). Нажмите кнопку Add Clause, чтобы сгенерировать Пролог-предложение для события. Название кнопки изменится на Edit Clause, когда код для события будет создан. Нажмите кнопку Edit Clause. Откроется окно редактора для файла MyProj.pro, в который добавлено предложение:
%BEGIN Task Window, id_test
task_win_eh(_Win,e_Menu(id_test,_ShiftCtlAlt),0):-!,
!.
%END Task Window, id_test

рис.16. Окно редактора кода
Поместите курсор в указанную точку, а затем щелкните правой кнопкой мыши и выберите и выберите команду Insert | Predicate Call | Window, Dialog or Toolbar
В появившевся диалоговом окне выберите из списка dlg_GetStr и нажмите ОК.

рис.17. Определение предиката для вставки
Вызов диалогового окна dlg_GetStr будет вставлен в текст и код предложения должен выглядеть следующим образом:
%BEGIN Task Window, id_test
task_win_eh(_Win,e_Menu(id_test,_ShiftCtlAlt),0):-!,
Msg="Message",
InitStr="",
Title="Title",
_NewSTRING=dlg_GetStr(Title,Msg,InitStr),
!.
%END Task Window, id_test

Для окончательной доработки внесите следующие изменения (выделены жирным шрифтом):
%BEGIN Task Window, id_test
task_win_eh(_Win,e_Menu(id_test,_ShiftCtlAlt),0):-!,
Msg="Введите Ваше имя", % строка-подсказка
InitStr="", % исходное значение вводимой пользователем строки
Title="Ввод имени пользователя", % заголовок окна
_NewSTRING=dlg_GetStr(Title,Msg,InitStr),% введенная
строка
_NewSTRING<>"", % если введенная строка не пустая,
write("Привет, ",_NewSTRING), % то выводится приветствие
!.
%END Task Window, id_test

4. Запустите проект на исполнение и протестируйте его.
ЗАДАНИЕ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
Доработайте проект, создав пункт меню Avtor, при выборе которого появляется диалоговое окно (dlg_Note) со сведениями об авторе проекта (Ф.И.О, группа)
2.2 Создание новых окон в проекте с использованием кнопок и полей ввода
Поля ввода (Edit Control) позволяют пользователю вводить данные. Обычно этот элемент представляет собой строку, которая содержит текст или число. Поле ввода может быть многострочным.
Для установки и получения содержимого поля ввода нужно использовать предикаты: String = win_GetText (Window), win_SetText (Window , string Text)
где Window – это оконный дескриптор элемента управления, который может быть получен вызовом предиката:
CtrlHndl=win_GetCtlHandle(Parent Window,CtrlId)
Командные кнопки (Push Button) позволяют пользователю выполнять различные действия: открывать и закрывать окна, выполнять расчеты и т.д.
Пример. Проект, позволяющий вычислить факториал введенного числа
Задание: создать проект, в котором при выборе пункта меню Factorial открывается окно, позволяющее ввести натуральное число и вычислить его факториал.
Решение
1. Создайте новый проект(Project | New Project).
2. Добавьте в главное меню новый пункт Factorial аналогично как в предыдущем примере).
3. Создайте новое окно. Для этого в окне проекта нажмите кнопку Window на левой панели инструментов, а затем – кнопку New справа (рис.18).

рис.18. Создание нового окна в проекте

Откроется окно Window Attributes (рис.19). Введите имя создаваемого окна Factorial и нажмите ОК.

рис.19. Диалоговое окно для установки атрибутов окна
4. Разместите на макете появившегося нового окна следующие компоненты (рис.20):
Static Text для вывода текста
Edit Control для ввода данных
Push Button для выполнения расчета


рис.20. Редактор окон

После размещения компонентов установите необходимые для каждого из них атрибуты:

а) для компонента Static Text, служащего для вывода надписи Введите число (имя-константа будет задано автоматически)(рис.21)


рис.21. Атрибуты компонента Static Text
б) для компонента Edit Control (поле ввода), который обеспечит ввод числа

рис.22. Атрибуты компонента Edit Control

в) для компонента Push Button (кнопка), при нажатии на который будет выполнен расчет и выведен результат (имя-константа будет задано автоматически)(рис.23)

рис.23. Атрибуты компонента Push Button

г) для компонента Static Text, необходимого для вывода результата

рис.24. Атрибуты компонента Static Text

5. Сгенерируйте стандартный код Visual Prolog для нового окна. Для этого в окне проекта нажмите кнопку Code Expert, когда выбрано окно Factorial. Откроется окно Dialog and Window Expert. Выберите исходный модуль Factorial.pro и нажмите кнопку Default Code(рис.25).

рис.25 Добавление кода по умолчанию в эксперте окон

Когда заданный по умолчанию код будет сгенерирован, станут доступны кнопки Add Clause, Edit Code и некоторые другие.

6. Запрограммируйте выбор пункта меню Factorial для вызова окна Factorial. Для этого в списке окон выберите Task Window , пункт Menu в списке Event Type и выделите строку id_factorial(имя пункта меню) в списке Event or Item. Нажмите кнопку Add Clause, чтобы сгенерировать Пролог-предложение для события. Название кнопки изменится на Edit Clause, когда код для события будет создан. Нажмите кнопку Edit Clause. Откроется окно редактора для файла Factorial.pro, в который добавлено предложение:
%BEGIN Task Window, id_factorial
task_win_eh(_Win,e_Menu(id_factorial,_ShiftCtlAlt),0):-!,
!.
%END Task Window, id_factorial
Допишите команду для открытия окна Factorial: win_factorial_Create(_Win). В результате должно получиться:
%BEGIN Task Window, id_factorial
task_win_eh(_Win,e_Menu(id_factorial,_ShiftCtlAlt),0):-!,
win_factorial_Create(Win),
!.
%END Task Window, id_factorial

7. Запрограммируйте нажатие кнопки Результат в окне Factorial для выполнения расчета и вывода результата. Для этого вызовите окно Dialog and Window Expert и в списке окон выберите Factorial. Выберите пункт Control в списке Event Type и выделите строку pb: idc_результат(имя кнопки). Нажмите кнопку Add Clause, а затем Edit Clause. Откроется окно редактора для файла Factorial.pro, в который добавлено предложение:
%BEGIN Factorial, idc_результат _CtlInfo
win_factorial_eh(_Win,e_Control(idc_результат,_CtrlType,_CtrlWin, _CtlInfo),0):-!,
!.
%END Factorial, idc_результат _CtlInfo
Допишите команды, необходимые для вычисления факториала и вывода результата. В результате должно получиться:
%BEGIN Factorial, idc_результат _CtlInfo
win_factorial_eh(_Win,e_Control(idc_результат, _CtrlType, _CtrlWin, _CtlInfo), 0):-!,
EDIT_WIN1=win_GetCtlHandle(_WIN,idc_ввод),
Text1=win_GetText(EDIT_WIN1), % считываем данные из поля ввода
str_int(Text1,N), % преобразует в числовое значение
fact(N,FN), % вычисляем факториал
str_int(StrFN,FN), % преобразуем в строковое значение
EDWIN=win_GetCtlHandle(_WIN,idct_вывод),
win_SetText(EDWIN,StrFN), % выводим результат
!.
%END Factorial, idc_результат _CtlInfo

8. Опишите правило вычисления факториала и предикат fact:
PREDICATES
win_factorial_eh : EHANDLER
fact(integer,integer)
CLAUSES
fact(0,1):-!.
fact(N,F):- N1=N-1,fact(N1,F1), F=N*F1.
win_factorial_Create(_Parent):-
win_Create(win_factorial_WinType,win_factorial_RCT,win_factorial_Title,
win_factorial_Menu,_Parent,win_factorial_Flags,win_factorial_eh,0).

9. Запустите проект на исполнение и протестируйте его.
ЗАДАНИЕ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
Доработайте проект, создав новый пункт меню Summa, при выборе которого появляется новое окно для ввода двух чисел и вычисления их суммы.
2.3 Использование элемента ListBox
ListBox (список)- это элемент управления, содержащий набор пунктов, которые может выбрать пользователь. В VPI есть несколько предикатов для работы со списками:
lbox_Add (Window, Index, Str) добавляет новую строку Str в список в позицию с индексом Index. Если Index равен -1, то строка добавляется в конец списка. Нумерация элементов списка начинается с 0, т.е. первый элемент списка имеет индекс 0, второй -1 и т.д.
lbox_Clear (Window) удаляет все элементы списка
lbox_Delete (Window, Index) удаляет элемент с указанным индексом
lbox_GetItem (Window, Index) возвращает элемент списка с указанным индексом
Integer=lbox_GetSelIndex(Window) возвращает индекс выбранного элемента. Предикат завершится неуспешно, если никакой элемент в списке не выбран
lbox_IsSel(Window, Index) завершается успешно или неспешно в зависимости от того, является ли текущим заданный элемент в списке

Пример. Проект, позволяющий формировать и редактировать списки данных.
Создать проект, содержащий элементы ListBox (список), Edit Control (поле ввода) для ввода новых данных, Push Button (кнопки) для добавления нового элемента в список и удаления выделенного элемента.

Решение
1. Создайте новый проект.
2. Добавьте в главное меню новый пункт Spisok .
3. Создайте новое окно. Для этого в окне проекта нажмите кнопку Window на левой панели инструментов, а затем – кнопку New справа. Откроется окно Window Attributes. Введите имя создаваемого окна Spisok и нажмите ОК.
4. Разместите на макете появившегося нового окна следующие компоненты: Edit Control, Push Button, ListBox (рис.26).

рис.26. Созданное окно Spisok
Задайте имена-константы для размещенных элементов, например для Edit Control - idc_edit, для ListBox - id_list_box, для кнопки ADD - idc_add, для кнопки DELETE - idc_delete
5. Сгенерируйте стандартный код Visual Prolog для нового окна. Для этого в окне проекта нажмите кнопку Code Expert, когда выбрано окно Spisok. Откроется окно Dialog and Window Expert. Выберите исходный модуль spisok.pro и нажмите кнопку Default Code.
6. Запрограммируйте выбор пункта меню Spisok для вызова окна Spisok. Для этого в списке окон выберите Task Window, пункт Menu в списке Event Type и выделите строку id_spisok (имя пункта меню) в списке Event or Item. Нажмите кнопку Add Clause, чтобы сгенерировать Пролог-предложение для события. Название кнопки изменится на Edit Clause, когда код для события будет создан. Нажмите кнопку Edit Clause. Откроется окно редактора для файла Spisok.pro, в который добавлено предложение:
%BEGIN Task Window, id_spisok
task_win_eh(_Win,e_Menu(id_spisok,_ShiftCtlAlt),0):-!,
!.
%END Task Window, id_spisok
Допишите команду для открытия окна Spisok: win_spisok_Create(_Win). В результате должно получиться:
%BEGIN Task Window, id_spisok
task_win_eh(_Win,e_Menu(id_spisok,_ShiftCtlAlt),0):-!,
win_spisok_Create(_Win),
!.
%END Task Window, id_spisok
7. Запрограммируйте нажатие кнопки ADD в окне Spisok для добавления нового элемента в список. Для этого вызовите окно Dialog and Window Expert (кнопка Code Expert) и в списке окон выберите Spisok. Выберите пункт Control в списке Event Type и выделите строку pb: idc_add(имя кнопки ADD). Нажмите кнопку Add Clause, а затем Edit Clause(рис.26).

рис.26. Созданное окно Spisok
Откроется окно редактора для файла Spisok.pro, в который добавлено предложение:
%BEGIN spisok, idc_add _CtlInfo
win_spisok_eh(_Win,e_Control(idc_add,_CtrlType,_CtrlWin,
_CtlInfo),0):-!,
!.
%END spisok, idc_add _CtlInfo
Допишите необходимые команды. В результате должно получиться:
%BEGIN spisok, idc_add _CtlInfo
win_spisok_eh(_Win,e_Control(idc_add,_CtrlType,_CtrlWin,
_CtlInfo),0):-!,
LBOXWIN = win_GetCtlHandle(_Win,id_list_box),
E_WINDOW = win_GetCtlHandle(_Win,idc_edit),
EDIT_STRING= win_GetText(E_WINDOW),
EDIT_STRING<>"",
lbox_Add(LBOXWIN,-1,EDIT_STRING),
!.
%END spisok, idc_add _CtlInfo

8. Аналогично запрограммируйте нажатие кнопки DELETE в окне Spisok для удаления выделенного элемента списка.
%BEGIN spisok, idc_delete _CtlInfo
win_spisok_eh(_Win,e_Control(idc_delete,_CtrlType,_
CtrlWin, _CtlInfo),0):-!,
LBOXWIN = win_GetCtlHandle(_Win,id_list_box),
Index = lbox_GetSelIndex(LBOXWIN),
lbox_Delete(LBOXWIN,Index),
!.
%END spisok, idc_delete _CtlInfo

9. Запустите проект на исполнение и протестируйте его.
ЗАДАНИЕ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
Доработайте проект проект следующим образом:
1) добавьте кнопку CLEAR, при нажатии на которую удаляется все содержимое списка (используйте предикат lbox_Clear);
2) добавьте компонент Static Text, который должен отображать выделенный элемент списка.
3 Создание экспертных систем средствами ПРОЛОГа
Экспертные системы (ЭС) - это сложные программные комплексы, аккумулирующие знания специалистов в конкретных предметных областях и тиражирующие этот эмпирический опыт для консультаций менее квалифицированных пользователей.
Построим небольшую экспертную систему, которая будет определять одну из нескольких рыб по признакам, указанным пользователем. Система будет задавать вопросы и строить логические выводы на основе полученных ответов.
Типичный диалог экспертной системы с пользователем может выглядеть следующим образом (рис.27):

рис.27. Диалог экспертной системы с пользователем

Первым шагом построения такой системы является обеспечение ее знаниями, необходимыми для выполнения рассуждений. Программа должна во время консультаций выводить заключения из информации, имеющейся в базе знаний, а также использовать новую информацию, полученную от пользователя. Поэтому минимальная ЭС должна включать:
базу знаний;
механизм вывода;
пользовательский интерфейс.
Разработку любой ЭС следует начать с исследования предметной области. Пусть на основе бесед с экспертом были получены следующие эмпирические правила:
1) ЕСЛИ
это отряд карпообразные и
И
у рыбы желто-золотистый окрас
И
губы с 4 усиками
ТО
это сазан
2) ЕСЛИ
это отряд карпообразные
И
у рыбы плавники с розовыми перьями

это плотва
3) ЕСЛИ
спинной плавник узкий
И
у рыбы желто-золотистый окрас
И
это отряд карпообразные

это лещ
4) ЕСЛИ
у рыбы нет зубов
И
одиночный спинной лучевой плавник
И
это костная рыба
И
это пресноводная рыба

это отряд карпообразные
5) ЕСЛИ
у рыбы есть костный скелет
ИЛИ
у рыбы есть жаберные крышки

это костная рыба
6) ЕСЛИ
рыба плавает в озерах
ИЛИ
рыба плавает в реках
ТО
это пресноводная рыба
Для создания базы знаний используем предикаты:
fish(symbol)
otrajd(symbol)
vid(symbol)
priznak(symbol)
Базу знаний будут составлять следующие правила:
fish("это сазан"):-
otrajd("отряд карпообразные"),
priznak("губы с 4 усиками").
fish("это плотва"):-
otrajd("отряд карпообразные"),
priznak("плавники с розовыми перьями").
fish("это лещ"):-
otrajd("отряд карпообразные"),
priznak("у рыбы желто-золотистый окрас"),
priznak("у рыбы спинной плавник узкий").
Необходимо предусмотреть, что искомой рыбы в базе знаний нет:
fish("Данной рыбы в базе знаний не обнаружено").
otrajd("отряд карпообразные"):-
vid("пресноводная рыба"),
vid("костная рыба"),
priznak("одиночный спинной лучевой плавник"),
priznak("у рыбы нет зубов").
vid("костная рыба"):-
priznak("у рыбы есть жаберные крышки");
priznak("у рыбы есть костный скелет").
vid("пресноводная рыба"):-
priznak("рыба плавает в реках или озерах").
Для хранения информации, полученной от пользователя, используются предикаты yes и no, составляющие внутреннюю базу фактов. Предикат yes служит для хранения фактов, соответствующих положительному ответу, а предикат no – для хранения отрицательных ответов. Т.е. предикат yes утверждает наличие какого-либо признака у рыбы, а no – отсутствие указанного признака. Эти предикаты объявляются в разделе внутренней базы фактов:
global facts
yes (symbol)
no (symbol)
Добавить новые факты во внутреннюю базу можно с помощью правила add_to_database, состоящего из двух частей. Первая часть добавляет факты, соответствующие положительному ответу (с клавиатуры вводится y’). Вторая часть правила добавляет факты, указывающие на отсутствие данного признака у рыбы.
add_to_database (Y,'y') :- assertz (yes (Y)).
add_to_database (Y,'n') :- assertz (no (Y)),fail.
Необходимо предусмотреть очистку внутренней базы фактов. Для этого создадим правило:
clear_from_database :- retract(yes(_)),fail.
clear_from_database :- retract(no(_)),fail.
Для проверки наличия у рыбы определенного признака создадим правило priznak (Y):
priznak (Y) :- yes (Y),!.
priznak (Y) :- not(no (Y)),
question (Y).
Формулировка вопроса, ввод ответа и сохранение соответствующего правила осуществляется с помощью правил:
answer :- fish(X),!,nl,
save("BF1.dbf"),
write (" Ответ: ",X,"."),nl.
question(Y) :-
write ("Вoпрос: ",Y,"?(y/n) "),
otvet(X),
write(X),nl,
add_to_database (Y,X).
otvet(C):-readchar(C).
И, наконец, правило begin, запускающее сеанс консультации:
begin :- write ("Ответьте на вопросы :"),nl,nl,
answer,
clear_from_database,
nl,nl,nl,nl,
exit.
Полный листинг программы выглядит следующим образом:
GLOBAL FACTS
yes (symbol)
no (symbol)
PREDICATES
fish(symbol)
otrajd(symbol)
vid(symbol)
begin
answer
question(symbol)
add_to_database(symbol,char)
otvet(char)
clear_from_database
priznak(symbol)
GOAL
begin.
CLAUSES
begin :-
write ("Ответьте на вопросы :"),nl,nl,
answer,
clear_from_database,
nl,nl,nl,nl,
exit.
answer :-
fish(X),!,nl,
save("BF1.dbf"),
write (" Ответ: ",X,"."),nl.
question(Y) :-
write ("Вoпрос: ",Y,"? "),
otvet(X),
write(X),nl,
add_to_database (Y,X).
otvet(C):-
readchar(C).
priznak (Y) :-
yes (Y),!.
priznak (Y) :-
not( no (Y)),
question (Y).
add_to_database (Y,'y') :-
assertz (yes (Y)).
add_to_database (Y,'n') :-
assertz (no (Y)),fail.
clear_from_database :- retract (yes(_)),fail.
clear_from_database :- retract (no(_)),fail.
fish("это сазан"):-
otrajd("отряд карпообразные"),
priznak("губы с 4 усиками").
fish("это плотва"):-
otrajd("отряд карпообразные"),
priznak("плавники с розовыми перьями").
fish("это лещ"):-
otrajd("отряд карпообразные"),
priznak("у рыбы желто-золотистый окрас"),
priznak("у рыбы спинной плавник узкий").
fish("Данной рыбы в базе знаний не обнаружено").
otrajd("отряд карпообразные"):-
vid("пресноводная рыба"),
vid("костная рыба"),
priznak("одиночный спинной лучевой плавник"),
priznak("у рыбы нет зубов").
vid("костная рыба"):-
priznak("у рыбы есть жаберные крышки");
priznak("у рыбы есть костный скелет").
vid("пресноводная рыба"):-
priznak(«рыба плавает в реках или озерах»).
ЗАДАНИЕ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ
1. Реализуйте данную программу в среде Visual Prolog и протестируйте ее.
2. Расширьте базу знаний экспертной системы, добавив следующие правила:
1) ЕСЛИ
у рыбы есть электрические органы
И
это отряд скаты

это электрический скат
2) ЕСЛИ
у рыбы на хвосте ядовитый шип
И
это отряд скаты

это скат-хвостокол
3) ЕСЛИ
у рыбы серо-коричневый окрас
И
у рыбы коническая морда
И
это отряд акулы

это гиганская акула
4) ЕСЛИ
это отряд акулы
И
рыба нападает на людей
И
у рыбы молотообразная морда

это рыба молот
5) ЕСЛИ
у рыбы нет хвостового плавника
И
у рыбы тонкий длинный хвост
И
это хрящевая рыба
И
это морская рыба

это отряд скаты
6) ЕСЛИ
это морская рыба
И
это хрящевая рыба
И
плавники не гибкие
И
хвост ассиметричный

это отряд акулы
7) ЕСЛИ
у рыбы нет плавательного пузыря
ИЛИ
у рыбы есть хрящевый скелет
ТО
это хрящевая рыба
8) ЕСЛИ
рыба плавает в морях
ТО
это морская рыба
3. Протестируйте полученную экспертную систему.
Литература

Адаменко А., Кучуков А. Логическое программирование и Visual Prolog.- СПб, 2003
Братко И. Программирование на языке ПРОЛОГ для искусственного интеллекта.- М., 1990.
Ин Ц., Соломон Д. Использование Турбо-Пролога. -М., 1993.
Клоксин У., Меллиш К. Программирование на языке ПРОЛОГ. -М., 1991.
Макаллистер Дж. Искусственный интеллект и Пролог на микроЭВМ.- М., 1990.
Янсон А. Турбо-Пролог в сжатом изложении. -М.,1990.









13PAGE 15


13PAGE 141315




окно проекта

кнопки для работы с компонентами проекта

компоненты проекта

эксперт кода

Введите имя проекта

Выберите Easywin

Установите Nondeterm

двойной щелчок

окно, отображающее текущие значения переменных

решение: X= anna

отдых_Россия(X)

отдыхает(X,Y)

X= sasha Y= antalia

отдыхает(sasha, antalia)

нет

россия(antalia).

X= anna Y= sochi

отдыхает(anna, sochi)

да

россия(sochi).

введите имя проекта

двойной щелчок

введите имя нового пункта меню &Test

выберите id_test

выберите события (Event) для меню (Menu)

Установите курсор в эту точку

выберите из списка dlg_GetStr

нажмите New

выберите Window

Введите имя окна Factorial

Static Text

Edit Control

Push Button

наберите надпись Введите число

имя-константа -
id_ввод

имя-константа -
idct_вывод

нажмите сюда

Выберите модуль Factorial.pro

Push Button

ListBox

Edit Control

выделите строку
pb: idc_add
(имя кнопки ADD)

Выберите Control в списке Event Type



Заголовок 1 Заголовок 2 Заголовок 315

Приложенные файлы

  • doc 287405
    Размер файла: 694 kB Загрузок: 0

Добавить комментарий