Скачиваний:
35
Добавлен:
22.05.2015
Размер:
145.92 Кб
Скачать

Лабораторная работа 3 Правила

В лабораторной работе №2 мы использовали предикаты, которые имели только связанные аргументы в своём определении. Такие предикаты являются, по сути, данными, хранимыми в программе. В настоящей лабораторной работе мы рассмотрим предикаты-правила. Правила имеют голову и тело. Голова правила выражает отношение между аргументами, которые являются свободными переменными. Тело правила определяет это отношение посредством вызова других предикатов, в которых эти свободные переменные связываются конкретными значениями. Если это происходит, то предикат завершается успехом, иначе – неуспехом и происходит откат назад.

Для выполнения примеров и заданий этой лабораторной работы следует либо создать новое консольное приложение, либо использовать консольное приложение из второй лабораторной работы, предварительно удалив из неё все примеры.

Родственные отношения

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

domains пол_чел = муж; жен.

Выразим данные о родственных отношениях недетерминированными фактами родитель/2, пол/2. Объявим эти факты следующим образом:

class facts родитель : (string Родитель, string Ребёнок). пол : (string Человек, пол_чел Пол).

Имя предиката и перечень аргументов разделяются двоеточием. Так как по умолчанию все факты базы данных являются недетерминированными, то режим nondeterm явно можно не указывать.

Обратите внимание, что пол определён через дополнительно введённый домен пол_чел. В принципе, мы имеем право назвать этот домен просто пол, и Пролог будет отличать домен пол и предикат пол. Однако, чтобы Вы на первых шагах освоения Пролога не путались где домен, а где предикат, мы будем называть их по разному.

В разделе clauses опишем небольшую группу людей, соединённых отношениями родитель/2, пол которых характеризуется отношением пол/2:

clauses

родитель("Вася","Рома").

родитель("Вася","Дима").

родитель("Рома","Лена").

родитель("Гена","Юля").

родитель("Клава","Рома").

родитель("Клава","Дима").

родитель("Лена","Коля").

родитель("Уля","Гена").

родитель("Валя","Лена").

пол("Вася",муж).

пол("Рома",муж).

пол("Гена",муж).

пол("Дима",муж).

пол("Коля",муж).

пол("Лена",жен).

пол("Юля",жен).

пол("Клава",жен).

пол("Уля",жен).

пол("Валя",жен).

Предложения можно располагать в одной строке, например, так:

clauses

родитель("Вася","Рома"). родитель("Вася","Дима").

родитель("Рома","Лена"). родитель("Гена","Юля").

родитель("Клава","Рома"). родитель("Клава","Дима").

родитель("Лена","Коля"). родитель("Уля","Гена").

родитель("Валя","Лена").

пол("Вася",муж). пол("Рома",муж). пол("Гена",муж).

пол("Дима",муж). пол("Коля",муж). пол("Лена",жен).

пол("Юля",жен). пол("Клава",жен). пол("Уля",жен).

пол("Валя",жен).

На данном этапе содержимое файла main.pro должно быть таким:

implement main

open core, console

domains

пол = муж; жен.

constants

className = "com/visual-prolog/main".

classVersion = "$JustDate: $$Revision: $".

class facts

родитель : (string Родитель, string Ребёнок).

пол : (string Человек, пол Пол).

clauses

classInfo(className, classVersion).

родитель("Вася","Рома").   родитель("Вася","Дима").

родитель("Рома","Лена").   родитель("Гена","Юля").

родитель("Клава","Рома").  родитель("Клава","Дима").

родитель("Лена","Коля").   родитель("Уля","Гена").

родитель("Валя","Лена").

пол("Вася",муж).  пол("Рома",муж).   пол("Гена",муж).

пол("Дима",муж).  пол("Коля",муж).   пол("Лена",жен).

пол("Юля",жен).   пол("Клава",жен).  пол("Уля",жен).

пол("Валя",жен).

run():-

init(),

succeed().

end implement main

goal

mainExe::run(main::run).

Скомпилируйте проект и убедитесь, что ошибки отсутствуют. На предупреждение о неиспользуемых предикатах пока можно не обращать внимание.

Теперь всё готово для определения правил. Правила объявляются в разделе предикатов с указанием режима детерминизма и потока аргументов. По умолчанию режим детерминизма procedure, а аргументы все входные.

Пример 1. Определим правило отец/2:

implement main

   open core, console domains пол = муж; жен. constants className = "com/visual-prolog/main". classVersion = "$JustDate: $$Revision: $". class facts родитель : (string Родитель, string Ребёнок). пол : (string Человек, пол Пол). class predicates отец : (string Отец, string Ребёнок) nondeterm anyflow. clauses classInfo(className, classVersion). отец(Родитель, Ребёнок) :- родитель(Родитель, Ребёнок),

Голова правила

пол(Родитель, муж).

Тело правила

родитель("Вася","Рома").   родитель("Вася","Дима"). родитель("Рома","Лена").   родитель("Гена","Юля"). родитель("Клава","Рома").   родитель("Клава","Дима"). родитель("Лена","Коля").   родитель("Уля","Гена"). родитель("Валя","Лена"). пол("Вася",муж).   пол("Рома",муж).   пол("Гена",муж). пол("Дима",муж).   пол("Коля",муж).   пол("Лена",жен). пол("Юля",жен).   пол("Клава",жен).   пол("Уля",жен). пол("Валя",жен). run():-    init(),    отец(Отец, Ребёнок),    write(Отец," - ",Ребёнок), nl,    fail;    write("Конец перебора"),    _=readchar(). end implement main goal

   mainExe::run(main::run).

Выполните программу и объясните полученные результаты.

Задание 1. Поменяйте местами в теле правила предикаты родитель(Родитель, Ребёнок) и пол(Родитель, муж). Запустите программу и объясните результаты.

Задание 2. Определите в программе новое правило мать/2.

Пример 2. Определим правило брат/2:

class predicates

брат : (string Человек, string Брат) nondeterm anyflow.

clauses

брат(Человек,Брат) :-

родитель(Родитель, Человек),

родитель(Родитель, Брат),

not(Человек=Брат),

пол(Брат, муж).

Выполните программу и определите, зачем использован предикат not(Человек=Брат). Для этого удалите из тела правила этот предикат и проанализируйте результаты выполнения программы. Заметка: предикат not(Человек=Брат) можно записать в виде Человек<>Брат.

Пример 3. Определим правило дедушка/2:

class predicates

дедушка : (string Дедушка, string Чадо) nondeterm anyflow.

clauses

дедушка(Дедушка,Чадо) :-

пол(Дедушка, муж),

родитель(Дедушка, Родитель),

родитель(Родитель, Чадо).

Обратите внимание на последовательность предикатов в теле правила. Она является оптимальной. Предикат пол(Дедушка, муж) на ранней стадии отсекает от дерева решений ненужные для этого отношения ветви.

Задание 3. Определите в программе новые правила сестра/2, бабушка/2, дядя/2, тётя/2, двоюродный_брат/2, двоюродная_сестра/2.

Задание 4. Определите в программе новые правила тесть/2, тёща/2, зять/2, сноха/2.

Пример 4. Определим правило сын/1:

class predicates

сын: (string Сын) nondeterm anyflow.

clauses

сын(Сын) :- пол(Сын, муж), родитель(_, Сын).

Здесь нами использована анонимная переменная, которая записывается знаком подчёркивания. Анонимная переменная не передаёт предикату никакие значения и не возвращает никаких значений, то ест она не используется при данном вызове предиката, но указывать её необходимо, так как предикат родитель/2 – двухарный, и поэтому нам надо указать значение какого именно аргумента для нас в данном вызове предиката безразлично – первого аргумента или второго.

Задание 5. Определите в программе новые правила дочь/1, внук/1, внучка/1, дед/1.

Задание повышенной трудности. Определите в программе новые правила отчим/2, мачеха/2, сводный_брат/2, сводная_сестра/2.

Соседние файлы в папке Лабораторные работы