Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Базы данных в программах на Прологе
В программах на Прологе имеется возможность хранить предикаты-факты, обрабатываемые программой, отдельно от самой программы. Файл, содержащий предикаты-факты, называется базой данных. Факты, хранящиеся в файле базы данных, объявляются в разделе global facts (или global database). Нестандартные типы данных, используемые в базе данных, должны быть объявлены в разделе global domains. В одной базе данных могут храниться факты, имеющие разные имена, разное количество аргументов и т.д. Все они должны быть объявлены в разделе global facts. Пример: Чтобы хранить в файле базы данных информацию о проектах и о сотрудниках, работающих над ними, потребуется следующее объявление (рис. 12):
global domains oplata=rub (integer, string); doll(integer) spisok=string*
global facts rabota (string, spisok) proekt (string, string, oplata)
Рис. 12. Объявление глобальных доменов и фактов.
Информация базы данных может храниться в текстовом файле с расширением *.dba. В каждой строке базы данных может содержаться только один факт. В базе данных не должно быть пустых строк, в том числе в конце базы данных (после последнего факта). Факты в базе данных должны быть набраны без пробелов. Точка в конце фактов не ставится. Загрузка базы данных Загрузка базы данных во время работы программы выполняется стандартным предикатом consult(имя_файла). Имя файла базы данных может задаваться константой (в этом случае оно должно быть заключено в кавычки) или переменной. Если используется переменная, то ей должно быть присвоено имя файла базы данных. Для указания имени файла в этом случае может использоваться предикат readln или операция присваивания. Если имя файла базы данных указывается в тексте программы (например, задается в предикате consult или присваивается переменной), то в нем необходимо использовать две наклонные черты (\\). Если имя файла вводится с клавиатуры с помощью оператора readln, то используется одна наклонная черта (\). Пусть, например, база данных, содержащая информацию о проектах и о сотрудниках, работающих над этими проектами, хранится в файле PROEKT.DBA на диске D: в папке ES. Тогда для загрузки базы данных можно использовать следующий предикат: consult(“d: \\es\\proekt.dba”). Перед предикатом consult рекомендуется указывать стандартный предикат retractall(_), удаляющий из памяти все факты базы данных (например, если они сохранились от предыдущего запуска программы). Пример: Предикат, запрашивающий имя базы данных и выполняющий ее загрузку (рис. 13). loading: - write(“Vvedite nazvanie”), readln(F), retractall(_), consult(F),!. loading.
Рис. 13. Загрузка базы данных.
По запросу “Введите имя базы данных” может быть введено, например, следующее имя: d: \es\proekt.dba. Второй клоз предиката loading, не выполняющий никаких действий, предусмотрен на случай, если пользователь откажется от загрузки, нажав клавишу ESC. В этом случае стандартный предикат readln завершается неудачей. Происходит возврат ко второму клозу предиката loading, и он доказывается успешно. Просмотр базы данных Прежде чем выполнять какие-либо действия в базе данных, необходимо загрузить ее в память компьютера, используя стандартный предикат consult. После этого предикаты-факты, загруженные из файла базы данных, могут использоваться в программе точно так же, как и факты, указанные в самой программе. Пример: Предикаты для просмотра перечня всех сотрудников, работающих над проектами (рис. 14): prosmotr_sotr: - rabota (F, S), write (“Фамилия: ”, F, " Проекты: ", S), nl, readchar(_), fail. prosmotr_sotr.
Рис. 14. Просмотр базы данных.
Работа этого предиката ничем не отличается от работы аналогичных предикатов. Изменение базы данных В ходе работы программы можно создавать новые факты базы данных или, наоборот, удалять имеющиеся. Поэтому базы данных в программах на Прологе называются динамическими. Для создания новых фактов используются предикаты asserta (добавление факта в начало базы данных), assertz (добавление факта в конец базы данных), assert (действует так же, как assertz). Пример: Предикат для добавления информации о новом сотруднике (рис. 15). Вводится фамилия сотрудника и список проектов, над которыми он работает. dobav_sotr: - write (" Фамилия: "), readln (Fam), write (" Проекты: "), readterm (spisok, Spis_pr), assert (rabota (Fam, Spis_pr)).
Рис. 15. Добавление информации о новом сотруднике.
Предикат assert создает в памяти новый факт rabota. Например, если введена фамилия Сергеев и список проектов [“П100”, ”П120”], то будет создан следующий факт: rabota(“Сергеев”, [“П100”, “П120”]). Аналогично можно реализовать предикат для добавления информации о проекте (рис. 16): dobav_pr: - write (" Шифр: "), readln (Shifr), write (" Заказчик: "), readln (Zak), write (" Оплата: "), readterm(oplata, Opl), assert (proekt(Shifr, Zak, Opl)).
Рис. 16. Добавление информации о проекте.
Следует напомнить, что в рассматриваемом примере третий аргумент предиката proekt (оплата) задается с помощью функтора. Например, если для некоторого проекта требуется указать, что его стоимость составляет 800 тыс. долларов и оплачивается в долларах, то по запросу “Оплата: ” необходимо ввести: doll(800). Если проект стоимостью 800 тыс. долларов оплачивается в рублях по курсу на 5 сентября 2002 года, то следует ввести: rub(800, “5.09.2002”). Для удаления фактов базы данных используются стандартные предикаты retract и retractall. Пример: Предикат для удаления информации о сотруднике (рис. 17). udal_sotr: - write (" Фамилия: "), readln (Fam), retractall (rabota (Fam, _)).
Рис. 17. Удаление информации о сотруднике.
Предикат retractall удаляет все факты, соответствующие указанным данным. В данном примере удаляются все факты rabota, где первым аргументом является указанная фамилия. Если таких фактов нет (например, фамилия введена неверно), то никаких изменений в базе данных не происходит, однако предикат rertractall считается доказанным успешно. Предикат retractall(_) удаляет из памяти все факты базы данных. Его рекомендуется указывать перед загрузкой базы данных, чтобы удалить из памяти факты, которые могли сохраниться от предыдущего запуска программы. Предикат retract удаляет из памяти только первый факт, соответствующий указанным данным. Если таких фактов нет, то никаких изменений в базе данных не происходит; однако доказательство предиката rertractall считается неудачным, и происходит возврат. Поэтому чаще применяется предикат retractall. Примечание. Важно обратить внимание, что все рассмотренные возможности изменения базы данных относятся только к фактам, загруженным в память компьютера, но не к содержимому файла базы данных. Например, если удалить какие-либо факты с помощью предикатов retract или retractall, то они удаляются только из памяти, но не из файла, хранящегося на диске. Чтобы изменить содержимое файла базы данных, необходимо сначала внести необходимые изменения в памяти, а затем сохранить базу данных. Сохранение базы данных Для сохранения содержимого базы данных в файле используется стандартный предикат save(имя_файла). Например, чтобы сохранить базу данных в файле PROEKT.DBA на диске D: в папке ES, можно использовать предикат: save(“d: \\es\\proekt.dba”). Можно также запрашивать имя базы данных, как показано в следующем примере. Пример: Предикат, запрашивающий имя файла и выполняющий сохранение базы данных в указанном файле (рис. 18). sohran: - write(“Введите имя базы данных для сохранения: ”), readln(F), save(F),!. sohran.
Рис. 18. Сохранение базы данных в указанном файле.
При вводе путевого имени файла необходимо использовать одиночные наклонные черты (\). Второй клоз предиката sohran обеспечивает его успешное доказательство в случае, если пользователь откажется от сохранения, нажав клавишу ESC. Дополнительные возможности применения баз данных Динамические базы данных широко применяются в Прологе для самых разнообразных операций по обработке данных. Предикаты assert и retract (или retractall) позволяют организовать временное хранение и изменение данных. Пример: Предикат, вычисляющий суммарную стоимость проектов, оплачиваемых в рублях и в долларах (рис. 19). summa: - retractall (sumdoll(_)), assert (sumdoll (0)), proekt (_, _, doll(S)), sumdoll (Sd), Sd1=Sd+S, retractall(sumdoll(_)), assert(sumdoll(Sd1)), fail. summa: - retractall (sumrub(_)), assert (sumrub (0)), proekt (_, _, rub(S, _)), sumrub (Sr), Sr1=Sr+S, retractall (sumrub(_)), assert (sumrub(Sr1)), fail. summa: - sumdoll (Sd), write (" Оплата в долларах: ", Sd), nl, sumrub (Sr), write (" Оплата в рублях: ", Sr), readchar(_).
Рис. 19. Вычисление суммарной стоимости проектов, оплачиваемых в рублях и в долларах.
При вызове этого предиката сначала происходит обращение к первому клозу. Стандартный предикат retractall (sumdoll(_)) удаляет из памяти факт базы данных sumdoll, если он там есть. Стандартный предикат assert (sumdoll(0)) создает факт базы данных sumdoll(0). Затем в базе данных отыскивается первый предикат proekt, где третьим аргументом является функтор doll; это предикат proekt (" П100", " Рубин", doll(1400)). Переменная S принимает значение 1400. В базе данных отыскивается предикат sumdoll(0), и переменная Sd принимает значение 0. Переменная Sd1 принимает значение Sd+S=0+1400=1400. Предикат retractall(sumdoll(_)) удаляет из памяти факт sumdoll(0), а предикат assert создает в памяти предикат sumdoll(1400). Предикат fail создает состояние искусственной неудачи; это требуется, чтобы найти сумму стоимостей по всем проектам. Происходит возврат к ближайшей «развилке», в данном случае - к предикату proekt (_, _, doll(S)). В базе данных отыскивается следующий предикат proekt, где третьим аргументом является функтор doll; это предикат proekt (" П70", " Горизонт", doll(500)). Переменная S принимает значение 500. В базе данных отыскивается предикат sumdoll. Так как имеется предикат sumdoll(1400), переменная Sd принимает значение 1400. Вычисляется переменная Sd1=Sd+S=1400+500=1900. Предикат retractall(sumdoll(_)) удаляет из памяти факт sumdoll(1400), а предикат assert создает в памяти предикат sumdoll(1900). Предикат fail снова создает состояние искусственной неудачи. Так как в базе данных больше нет фактов proekt с функторами doll, происходит переход ко второму клозу предиката summa. Итак, по окончании обработки первого клоза предиката summa в базе данных создан факт sumdoll(1900). Таким образом, подсчитана сумма стоимостей проектов, оплачиваемых в долларах. Второй клоз предиката summa обрабатывается аналогично первому. В результате создается факт sumrub(1800), содержащий сумму стоимостей проектов, оплачиваемых в рублях. В третьем клозе предиката summa выполняется вывод результатов на экран. Факты базы данных sumdoll и sumrub должны быть объявлены в разделе global facts (рис. 20): global facts sumdoll (real) sumrub (real) Рис. 20. Объявление глобально фактов sumdoll и sumrub. Примечание. Напомним, что в Прологе невозможны операции вида S=S+X. Такая операция интерпретируется как сравнение значений S и S+X и поэтому всегда завершается неудачей. Из-за этого для реализации суммирования потребовалось использовать факты динамической базы данных. Программа для работы с базой данных Рассмотрим разработку программы, позволяющей выполнять различные операции с базой данных о проектах и сотрудниках. Приведем целевой предикат, создающий простейшее меню операций с базой данных (рис. 21) и обеспечивающий выполнение выбранных операций (рис. 22).
Рис. 21. Меню для работы с базой данных.
goal start.
clauses start: -clearwindow, makewindow (1, 7, 7, " База данных", 0, 0, 14, 40), repeat, clearwindow, write (" 1 - загрузка"), nl, write (" 2 - добавление"), nl, write (" 3 - удаление"), nl, write (" 4 - просмотр"), nl, write (" 5 - сохранение"), nl, write (" 6 - выход"), nl, write (" 7 - поиск"), nl, write (" Введите номер операции: "), readint (N), obrab (N), removewindow. Рис. 22. Создание простейшего меню операций с базой данных.
Стандартный предикат makewindow создает на экране окно. Смысл аргументов предиката следующий: 1 - номер окна; 7, 7 - цвет окна и рамки (черное окно, белая рамка), “База данных” - заголовок окна (выводится сверху); 0, 0 – координаты левого верхнего угла окна; 14, 40 – высота и ширина окна. Предикат repeat необходим для того, чтобы операции с базой данных могли выполняться многократно. Предикат clearwindow очищает окно. Предикаты write выводят на экран элементы меню (возможные операции с базой данных), а предикат readint запрашивает номер желаемой операции. Предикат obrab реализует операции, выбираемые из меню. Он должен иметь по меньшей мере десять клозов (по числу операций в меню). При этом все клозы предиката obrab (кроме клоза для операции выхода, соответствующего номеру 6) должны заканчиваться неудачей. В этом случае выполняется возврат к предикату repeat. Он успешно доказывается, на экран снова выводится меню, и повторяется запрос желаемой операции. Реализация предиката obrab (рис. 23): obrab(1): - makewindow(2, 7, 7, " Загрузка", 12, 0, 3, 60), zagruzka, removewindow, shiftwindow(1),!, fail. obrab(2): - makewindow(3, 7, 7, " Добавление", 12, 0, 10, 80), dobav, removewindow, shiftwindow(1),!, fail. obrab(3): - makewindow(4, 7, 7, " Удаление", 12, 0, 10, 80), udal, removewindow, shiftwindow(1),!, fail. obrab(4): - makewindow(5, 7, 7, " Просмотр", 12, 0, 10, 80), prosmotr, removewindow, shiftwindow(1),!, fail. obrab(5): -makewindow(6, 7, 7, " Сохранение", 12, 0, 3, 60), sohran, removewindow, shiftwindow(1),!, fail. obrab(6). obrab(7): -makewindow(7, 7, 7, " Поиск", 12, 0, 10, 80), poisk, removewindow, shiftwindow(1),!, fail.
Рис. 23. Реализация предиката obrab.
Рассмотрим клоз obrab(4). Он будет доказываться, если на запрос " Введите номер: " будет введен номер 4, т.е. выбрана операция просмотра. Предикат makewindow создает окно для просмотра. Затем вызывается предикат prosmotr, непосредственно выполняющий просмотр. Для нормальной работы программы он должен доказываться успешно. Предикат removewindow удаляет с экрана текущее окно (окно просмотра). Предикат shiftwindow(1) выполняет возврат курсора в окно с номером 1 (окно меню). Предикат fail вызывает состояние искусственной неудачи, в результате чего происходит возврат к предикату repeat и повторение работы с меню. Предикат отсечения (!) указан только для того, чтобы при возврате не рассматривались остальные клозы предиката obrab. Предикаты zagruzka, dobav, udal, prosmotr, sohran, poisk рассмотрены выше. Все используемые предикаты должны быть объявлены в разделе predicates.
Контрольное задание:
Подготовить файл базы данных, содержащий несколько фактов. В структуре фактов базы данных должны быть использованы данные типа «список», «функтор», «альтернативный домен». Разработать и отладить программу, реализующую следующие операции с базой данных: загрузку, просмотр базы данных, добавление фактов в базу данных, удаление фактов из базы данных (по заданному условию), сохранение базы данных, поиск. Программа должна иметь меню и систему окон. Тематика базы данных соответствует выбранным вами вариантам курсовых работ.
Контрольные вопросы:
1. Дайте определение языка Пролог. 2. Сформулируйте понятие факта. 3. Перечислите виды переменных. 4. Какие основные разделы программы на языке Пролог вы знаете? 5. Назовите дополнительные разделы программы на языке Пролог. 6. Дайте определение предиката. 7. Перечислите встроенные предикаты. 8. Перечислите способы организации циклов на Прологе.
|