Примеры программ на прологе

Существует множество реализации языка Пролог для разных классов вычислительных систем. Для выполнения лабораторных работ используется программный продукт Visual Prolog v.5.2 Personal Edition for Windows.

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

/* секция объявления доменов */

/* секция объявления динамических баз данных */

/* секция объявления предикатов */

/* предложения (факты и правила) */

/* подцель_1, подцель_2, и т. д. */

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

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

Пролог — попытка объяснить без программирования

Рис. 1.2.Пример программы на Прологе

Пролог-программа может использовать комментарии, которые не влияют на выполнение программы, но могут оказать помощь человеку, читающему программу. Пролог игнорирует произвольное число строк, заключенное между символами /* и */. Все, что находится между % и концом строки, также рассматривается как комментарий.

Практикум 1-1

Запустите систему Пролог.

Создайте программу «Родственные отношения» в соответствии с рис.1.1., рис.1.2.

Проверьте работу программы, ответив на вопросы:

  1. Является ли Ольга родителем Игоря?
  2. Кто родители князя Игоря?
  3. Есть ли у Олега дети?
  4. Чьим внуком является Ярослав Мудрый?
  5. Сколько детей у Анны Византийской?

Практикум 1-2

Добавьте правила, для определения родственных связей

Проверьте работу программы, ответив на вопросы:

  1. Кто отец Владимира Красное Солнышко??
  2. Перечислить всех матерей?
  3. Сколько братьев у Ярослава Мудрого?
  4. Был ли сын у Ярополка?
  5. Был ли дядя у Мстислава Храброго?

Практикум 1-3

Самостоятельно сформулируйте пять запросов к базе знаний

Оформите Отчет по лабораторной работе

Контрольное задание 1 Исходные данные

Номер варианта индивидуального задания выбирается по последней цифре номера зачетной книжки (номера студенческого билета).

В индивидуальном задании студенту для описания базы фактов предлагается минимальный набор родственных отношений в соответствии с вариантом:

ребенок/2. женщина /1.

Значками «/1», «/2», «/3» задается арность отношения или, говоря в терминах предметной области, количество личностей в отношении.

  • отношение «мужчина/1» характеризует такой факт как «Виктор является мужчиной» или на Пролог
  • отношение «отец/2» характеризует родственное отношение «Виктор отец Андрея» или на Пролог

отец (“Виктор”, “ Aндрей”);

Три примера решения задачек на Прологе

  • отношение «сын/3» характеризует родственной отношение «Андрей сын Виктора и Аллы» или на Пролог

сын (“Андрей”, “Виктор”, “Алла”);

  • отношение «родитель/3» характеризует родственной отношение «Виктор и Алла родители Андрея» или на Пролог

родители (“Виктор”, “Алла”, “Андрей”).

Примечание: Указанный в задании минимальный набор фактов родственных отношений может быть расширен дополнительными фактами, но необходимость подобного действия необходимо обосновать.

Источник: studfile.net

Пролог (Prolog) для начинающих, для «чайников», для Dummies

Друзья! В связи с большим количеством писем по данному разделу, хочу сообщить, что в настоящее время (апрель 2020 года) планирую активно развивать раздел, посвящённый SWI–Prolog-у. Данный Prolog может показать кому-то не очень удобным в освоении и использовании, но это только на первый взгляд. Это достаточно мощная и активно развивающаяся реализация Prolog и к тому же — бесплатная. Конечно, это только моё мнение

 Архитектура Сознания - ПРОКАЧАЙ!

Пролог (Prolog) для начинающих, для «чайников», для Dummies — это руководство для начинающих, которые хотели бы изучить язык программирования Пролог (Prolog). В данном руководстве собран богатый теоретический и практический материал. Все статьи проиллюстрированы работающими программами на Пролог (Prolog). Большинство программ протестированы в среде SWI–Prolog, Turbo Prolog 2.0, а также в EZY Prolog. Описание синтаксиса дано для Turbo Prolog 2.0.

Читайте также:
Как запустить программу х86 на х64

Источник: verim.org

Пример базы данных на Prolog (CRUD)

Соответствующая ER-диаграмма приведена на рисунке:

Пусть, система предоставляет оператору следующие функции:

  1. просмотр всех людей, отделов, карточек;
  2. добавление человека, добавление отдела, устройство на работу, увольнение;
  3. изменение ФИО человека, изменение ID начальника отдела;
  4. удаление людей и подразделений, созданных по ошибке (в которые никто не пытался устраиваться);
  5. удаление карточек.

При выполнении этих операций стоит учитывать, что:

  1. id в каждой таблице не должны повторяться (желательно снять эту проблему с головы оператора и реализовать что-то типа AUTO_INCREMENT из SQL);
  2. нельзя уволить сотрудника, который не был устроен на работу (при этом надо кроме id учитывать подразделение);
  3. нельзя устроить человека в компанию если он уже в ней работает (в любом отделе);
  4. наличие людей можно проверить по карточкам приема и увольнения, при этом надо учитывать, что человек может уволиться, а затем — устроиться на работу опять (перевод между отделами выполняется оператором именно так).
  5. нельзя удалить человека, на которого заводилась хоть одна карточка приема (иначе эти карточки станут логически невалидными);
  6. 6нельзя удалить человека, если он является руководителем подразделения;
  7. нельзя удалить подразделение, в которое кто-либо устроен (кроме руководителя) или был устроен;
  8. для создания нового подразделения надо указать id начальника, который в этот момент должен быть не устроен на работу (иначе выйдет, что он работает в фирме в двух отделах одновременно — см. п. 3).
  9. если пункт «создать подразделение» или «карточку» выбран по ошибке — оператор должен ввести отрицательное значение id в качестве id_начальника и id_человека, соответственно — программа вернется в главное меню.
  10. при успешном устройстве человека на работу система запросит текущую дату, так как создается карточка устройства начальника на работу (см. п. 8), лучше было бы брать эту дату из системных параметров, но не получилось.

2 Реализация системы

Реализация выполнена на языке Visual Prolog 5.2, но совместима с Turbo Prolog. Ее не сложно портировать на другие диалекты, например SWI Prolog.

2.1 Типы данных, точка входа

Чтобы реализовать такую систему, сначала опишем типы данных:

DOMAINS % dd, mm, yyyy: date_type = date(integer, integer, integer) % id, name: man_type = man(integer, string) % id, id_chief, name: subdivision_type = subdivision(integer, integer, string) % id_card, id_man, id_subdivision, date, staff_name: recruiting_card_type = recruiting_card(integer, integer, integer, date_type, string) % id_card, id_man, id_subdivision, date: ejection_card_type = ejection_card(integer, integer, integer, date_type)

Для каждой «таблицы» в базе заведет тип объектов в базе данных:

database — human_relations man_db(man_type) subdivision_db(subdivision_type) recruiting_db(recruiting_card_type) ejection_db(ejection_card_type)

Точка входа программы (секция goal) выполняет очистку локальной БД, загрузку данных с базы в файле и запуск меню:

GOAL clear_db, !, load_db, !, menu(0).

2.2 Реализация меню

Теперь можно описать меню (тут приведено не полностью). Правило menu(0) вывод на экран меню и запрашивает номер пункта, после чего — переходит к соответствующему пункту (правилу). Каждое из правил-обработчиков выполняет свою работу, отсечение и рекурсивно вызывает menu(0) . Если пользователь ввел некорректный номер пункта меню — сработает последнее правило — menu(_) , выводящее на экран текст ошибки и также переходящее к menu(0) :

menu(0):- write(«enter: n»), write(«t0 — exitn»), write(«t11 — add mann»), write(«t12 — add subdivisionn»), write(«t13 — recruitingn»), write(«t14 — ejectionn»), nl, write(«t21 — print all mansn»), write(«t22 — print all subdivisionsn»), write(«t23 — print all man for subdivisionn»), nl, write(«t31 — remove mann»), write(«t32 — remove subdivisionn»), write(«t33 — remove recruiting cardn»), write(«t34 — remove ejection cardn»), nl, write(«t41 — edit man namen»), write(«t42 — edit subdivision’s chiefn»), write(«: «), readint(MenuPoint), !, NOT(MenuPoint = 0), menu(MenuPoint). menu(11):- !, read_man(Man), assert(man_db(Man)), save_db, menu(0). % . menu(_):- !, write(«wrong menu point. Retry. n»), nl, menu(0).

Читайте также:
Программа топоматик робур это

Пункты меню, меняющие локальную базу данных вызывают предикат save_db .

2.3 Предикаты для работы с БД (в памяти и файле)

Для работы с базой написаны 3 вспомогательных предиката — для:

  1. очистки локальной БД с помощью retractall ;
  2. загрузки базы с файла — при этом сначала выполняется поиск соответствующего файла на диске с помощью встроенной функции existfile , а затем — загрузка с помощью consult ;
  3. сохранение локальной базы в файле выполняется с помощью встроенного предиката save

clear_db:- retractall(_, human_relations). load_db:- existfile(«db.dba»), consult(«db.dba», human_relations), !, write(«loaded»), nl; write(«db not loaded»), nl. save_db:- save(«db.dba», human_relations).

Для генерации неиспользуемых идентификаторов (как AUTO_INCREMENT ), написаны такие функции:

get_man_id(Pivot, Id):- man_db(man(Pivot, _)), !, NextPivot = Pivot + 1, get_man_id(NextPivot, Id); Id = Pivot. get_subdivision_id(Pivot, Id):- subdivision_db(subdivision(Pivot, _, _)), !, NextPivot = Pivot + 1, get_subdivision_id(NextPivot, Id); Id = Pivot. get_recruiting_id(Pivot, Id):- recruiting_db(recruiting_card(Pivot, _, _, _, _)), !, NextPivot = Pivot + 1, get_recruiting_id(NextPivot, Id); Id = Pivot. get_ejection_id(Pivot, Id):- ejection_db(ejection_card(Pivot, _, _, _)), !, NextPivot = Pivot + 1, get_ejection_id(NextPivot, Id); Id = Pivot.

2.4 Остальные предикаты

Предикаты для работы с датой (read_int_between, read_date, less) нужно взять и добавить к приведенному ниже исходному коду из темы «Обработка даты и времени в Prolog«.

Остальные предикаты приведены без пояснений, однако стоит отметить, что проблемы возникли при реализации пункта menu(42) — при смене руководителя отдела мало удалить старую запись отдела и добавить новую (с новым ID руководителя), но также:

  • надо проверить, что новый руководитель существует и не работает (выполняет предикат read_free_man_id);
  • проверить что отдел с таким номером вообще существует (read_existed_subdivision_id);
  • старого руководителя надо уволить, а нового устроить — для этого надо добавить карточки увольнения и устройства на работу;
  • для заполнения карточек нужна дата — поэтому она запрашивается у оператора (read_date).

3 Исходный код программы

Исходный код программы кроме функций работы со временем (см. выше):

DOMAINS % dd, mm, yyyy: date_type = date(integer, integer, integer) % id, name: man_type = man(integer, string) % id, id_chief, name: subdivision_type = subdivision(integer, integer, string) % id_card, id_man, id_subdivision, date, staff_name: recruiting_card_type = recruiting_card(integer, integer, integer, date_type, string) % id_card, id_man, id_subdivision, date: ejection_card_type = ejection_card(integer, integer, integer, date_type) database — human_relations man_db(man_type) subdivision_db(subdivision_type) recruiting_db(recruiting_card_type) ejection_db(ejection_card_type) PREDICATES nondeterm menu(integer) load_db clear_db save_db read_int_between(integer, integer, integer) read_date(date_type) less(date_type, date_type) nondeterm get_man_id(integer, integer) nondeterm get_subdivision_id(integer, integer) nondeterm get_recruiting_id(integer, integer) nondeterm get_ejection_id(integer, integer) read_man(man_type) read_subdivision(subdivision_type) read_free_man_id(integer) check_free_man_id(integer, integer) read_existed_subdivision_id(integer) check_subdivision_id(integer, integer) is_worker(integer) % id is_dismissed_from(integer, date_type) % id man, date from is_dismissed_from(integer, integer, date_type) % id man, id subdivision, date from nondeterm work_in(integer, integer) % id man, id subdivision worker_card(integer, recruiting_card_type) % last card for user recruiting_chief(subdivision_type) print_subdivisions print_peoples print_workers_in(integer) read_recruting_card(recruiting_card_type) read_ejection_card(ejection_card_type) remove_man try_remove_man(integer) remove_subdivision try_remove_subdivision(integer) remove_recruting_card remove_ejection_card CLAUSES clear_db:- retractall(_, human_relations). load_db:- existfile(«db.dba»), consult(«db.dba», human_relations), !, write(«loaded»), nl; write(«db not loaded»), nl. save_db:- save(«db.dba», human_relations). get_man_id(Pivot, Id):- man_db(man(Pivot, _)), !, NextPivot = Pivot + 1, get_man_id(NextPivot, Id); Id = Pivot. get_subdivision_id(Pivot, Id):- subdivision_db(subdivision(Pivot, _, _)), !, NextPivot = Pivot + 1, get_subdivision_id(NextPivot, Id); Id = Pivot. get_recruiting_id(Pivot, Id):- recruiting_db(recruiting_card(Pivot, _, _, _, _)), !, NextPivot = Pivot + 1, get_recruiting_id(NextPivot, Id); Id = Pivot. get_ejection_id(Pivot, Id):- ejection_db(ejection_card(Pivot, _, _, _)), !, NextPivot = Pivot + 1, get_ejection_id(NextPivot, Id); Id = Pivot. read_man(man(Id, Name)):- write(«name: «), readln(Name), get_man_id(0, Id), !. read_free_man_id(ChiefID):- write(«man id: «), readint(ID), check_free_man_id(ID, ChiefID). check_free_man_id(CheckedID, _):- CheckedID < 0, !, fail. check_free_man_id(CheckedID, CheckedID):- man_db(man(CheckedID, _)), NOT(is_worker(CheckedID)), !. check_free_man_id(_, ID):- read_free_man_id(ID). read_subdivision(subdivision(Id, ChiefId, Name)):- read_free_man_id(ChiefId), get_subdivision_id(0, Id), !, write(«subdivision name: «), readln(Name). is_dismissed_from(ManID, Date):- ejection_db(ejection_card(_, ManID, _, EjectionDate)), less(Date, EjectionDate), !. is_dismissed_from(ManID, SubdivisionID, Date):- ejection_db(ejection_card(_, ManID, SubdivisionID, EjectionDate)), less(Date, EjectionDate), !. is_worker(ManID):- recruiting_db(recruiting_card(_, ManID, _, RecrutingDate, _)), NOT(is_dismissed_from(ManID, RecrutingDate)), !. work_in(ManID, SubdivisionID):- recruiting_db(recruiting_card(_, ManID, SubdivisionID, RecrutingDate, _)), NOT(is_dismissed_from(ManID, SubdivisionID, RecrutingDate)). worker_card(ManID, RecrutingCard):- recruiting_db(RecrutingCard), RecrutingCard = recruiting_card(_, ManID, SubdivisionID, RecrutingDate, _), NOT(is_dismissed_from(ManID, SubdivisionID, RecrutingDate)), !. recruiting_chief(subdivision(SubdivisionID, ChiefID, _)):- read_date(Date), get_recruiting_id(0, CardID), !, assert(recruiting_db(recruiting_card(CardID, ChiefID, SubdivisionID, Date, «chief»))). read_existed_subdivision_id(SubdivisionID):- write(«subdivision Id: «), readint(ID), check_subdivision_id(ID, SubdivisionID). check_subdivision_id(ID, SubdivisionID):- ID < 0, !, fail; subdivision_db(subdivision(ID, _, _)), !, SubdivisionID = ID; read_existed_subdivision_id(SubdivisionID). read_recruting_card(recruiting_card(CardID, ManID, SubdivisionID, Date, Staff)):- get_recruiting_id(0, CardID), read_free_man_id(ManID), read_existed_subdivision_id(SubdivisionID), read_date(Date), write(«staff: «), readln(Staff), !. read_ejection_card(ejection_card(CardID, ManID, SubdivisionID, Date)):- read_free_man_id(ManID), read_existed_subdivision_id(SubdivisionID), work_in(ManID, SubdivisionID), get_ejection_id(0, CardID), !, read_date(Date). print_peoples:- man_db(man(Id, Name)), write(Id), write(«t»), write(Name), nl, fail; !. print_subdivisions:- subdivision_db(subdivision(ID, ChiefID, Name)), write(ID), write(«t»), write(ChiefID), write(«t»), write(Name), nl, fail; !. print_workers_in(SubdivisionID):- work_in(ManID, SubdivisionID), man_db(man(ManID, ManName)), worker_card(ManID, recruiting_card(CardID, ManID, SubdivisionID, Date, Staff)), write(CardID), write(«t»), write(ManName), write(«(«), write(ManID), write(«)t»), write(Staff), write(«t»), write(Date), write(«n»), fail; !. remove_man:- write(«enter man id: «), readint(ID), is_worker(ID), !, try_remove_man(ID) ; write(«no such workern»). try_remove_man(ManID):- NOT(recruiting_db(recruiting_card(_, ManID, _, _, _))), NOT(ejection_db(ejection_card(_, ManID, _, _))), retract(man_db(man(ManID, _))), !, write(«removedn»); write(«This man was recruted. You need to remove all cardsn»). remove_subdivision:- write(«enter subdivision id: «), readint(ID), subdivision_db(subdivision(ID, _, _)), !, try_remove_subdivision(ID), ! ; write(«no such subdivisionn»). try_remove_subdivision(SubdivisionID):- findall(ManID, recruiting_db(recruiting_card(_, ManID, SubdivisionID, _, _)), Workers), Workers = [_], NOT(ejection_db(ejection_card(_, _, SubdivisionID, _))), retract(subdivision_db(subdivision(SubdivisionID, _, _))), !, write(«removedn»); write(«You need to remove all cards for the subdivision before remove itn»). remove_recruting_card:- write(«card id: «), readint(ID), retract(recruiting_db(recruiting_card(ID, _, _, _, _))), !. remove_ejection_card:- write(«card id: «), readint(ID), retract(ejection_db(ejection_card(ID, _, _, _))), !. menu(0):- write(«enter: n»), write(«t0 — exitn»), write(«t11 — add mann»), write(«t12 — add subdivisionn»), write(«t13 — recruitingn»), write(«t14 — ejectionn»), nl, write(«t21 — print all mansn»), write(«t22 — print all subdivisionsn»), write(«t23 — print all man for subdivisionn»), nl, write(«t31 — remove mann»), write(«t32 — remove subdivisionn»), write(«t33 — remove recruiting cardn»), write(«t34 — remove ejection cardn»), nl, write(«t41 — edit man namen»), write(«t42 — edit subdivision’s chiefn»), write(«: «), readint(MenuPoint), !, NOT(MenuPoint = 0), menu(MenuPoint). menu(11):- !, read_man(Man), assert(man_db(Man)), save_db, menu(0). menu(12):- read_subdivision(Subdivision), !, assert(subdivision_db(Subdivision)), recruiting_chief(Subdivision), save_db, menu(0) ; write(«subdivision not createdn»), !, menu(0). menu(13):- read_recruting_card(Card), assert(recruiting_db(Card)), !, save_db, menu(0) ; write(«card not createdn»), !, menu(0). menu(14):- read_ejection_card(Card), assert(ejection_db(Card)), !, save_db, menu(0) ; write(«The man don’t work in this subdivisionn»), menu(0), !. menu(21):- !, write(«idtnamen»), nl, print_peoples, menu(0). menu(22):- !, write(«idtchief idnnamen»), nl, print_subdivisions, menu(0). menu(23):- read_existed_subdivision_id(SubdivisionID), !, write(«idtworkertstafftfromn»), nl, print_workers_in(SubdivisionID), menu(0) ; write(«rejectedn»), !, menu(0). menu(31):- remove_man, !, write(«removed OK»), nl, save_db, menu(0) ; !, menu(0). menu(32):- remove_subdivision, !, save_db, menu(0) ; !, menu(0). menu(33):- remove_recruting_card, !, save_db, write(«removedn»), menu(0) ; !, write(«no such cardn»), menu(0). menu(34):- remove_ejection_card, !, save_db, write(«removedn»), menu(0) ; !, write(«no such cardn»), menu(0). menu(41):- write(«man id: «), readint(ManID), man_db(man(ManID, _)), !, write(«new name: «), readln(Name), retract(man_db(man(ManID, _))), assert(man_db(man(ManID, Name))), !, save_db, write(«changedn») ; !, write(«no such mann»), menu(0). menu(42):- read_existed_subdivision_id(SubdivisionID), read_free_man_id(NewChiefD), !, retract(subdivision_db(subdivision(SubdivisionID, OldChiefID, SubdivisionName))), assert(subdivision_db(subdivision(SubdivisionID, NewChiefD, SubdivisionName))), read_date(Date), get_ejection_id(0, EjectionCardID), assert(ejection_db(ejection_card(EjectionCardID, OldChiefID, SubdivisionID, Date))), get_recruiting_id(0, RecrutingCardID), assert(recruiting_db(recruiting_card(RecrutingCardID, NewChiefD, SubdivisionID, Date, «chief»))), !, write(«changedn»), save_db, menu(0) ; !, write(«rejected. n»), menu(0). menu(_):- !, write(«wrong menu point. Retry. n»), nl, menu(0). GOAL clear_db, !, load_db, !, menu(0).

Читайте также:
DEXP hellscream 100 программа для настройки

Источник: pro-prof.com

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru