Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Solomon.doc
Скачиваний:
16
Добавлен:
08.05.2019
Размер:
3.38 Mб
Скачать

Глава 9. Создание динамических баз данных

9.1. Введение

В предыдущих главах было описано большинство средств

Турбо-Пролога. И теперь,научившись создавать динамические ба-

зы данных, читатель получит возможность применять Турбо-Про-

лог во всей его мощи. В настоящей главе будут представлены

некоторые основополагающие принципы создания динамических баз

данных, а также средства работы с ними. Навыки по применению

этой техники будут приобретены при написании на Турбо-Прологе

программ систем управления базами данных.

Демонстрационные программы данной главы используют ста-

тистику о футбольных командах (имеется в виду американский

футбол), игроках команд и тренерах. Это не помешает применять

возможности Турбо-Пролога для конструирования банков данных,

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

цены на распродажах, информацию об индексах акций, включая

инвентарные номера, размеры, названия фирм, выпустивших ак-

ции, коды и цены и т.д.

Кажется, все, что почерпнуто из первой части книги, бу-

дет в той или иной мере задействовано в материале этой главы

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

нение новых приемов программирования, упражнения, программы -

все будет подводить к одной, объединяющей все возможности

программе, завершающей каждую из последующих глав.

Первый раздел настоящей главы дает общее представление

об основных концепциях баз данных.Это облегчит начальный шаг

на пути к работе с базами данных Турбо-Пролога. Если читатель

уже знаком с этим материалом, то первую часть можно лишь бег-

ло пролистать.

Во втором разделе описан проект базы данных на Тур-

бо-Прологе, которая располагается в оперативной памяти компь-

ютера. Проект реализован в виде программы, так что ее можно

запустить на счет и посмотреть, как взаимодействуют ее сос-

тавные части.

В третьем разделе представлен проект базы данных, рас-

полагающейся на диске. Обсуждаются средства Турбо-Пролога,

необходимые для воплощения в жизнь этого проекта, и, опять,

приводится законченная программа, реализующая эту базу дан-

ных.

9.2. Основные сведения о базах данных

Программы баз данных (БД) на Турбо-Прологе, которые бу-

дут созданы и с которыми вы будете работать в настоящей гла-

ве, есть частный случай систем управления базами данных

(СУБД). СУБД являются компьютеризованной системой хранения

информации. Данные в БД представляют собой набор фактов и

цифр, записанных в доступной для компьютера форме. Эта упоря-

доченная совокупность и является содержимым базы данных.

СУБД должны предоставлять возможность добавления, удале-

ния и корректировки данных. Эти функции реализуются специаль-

ными программами. Совокупность базы данных и функциональных

программ образует систему управления базой данных.

Существуют три хорошо известные модели организации БД.

Это иерархическая модель, сетевая модель и реляционная мо-

дель. В иерархической модели данные хранятся в иерархии клас-

теров. В сетевой данные содержатся в виде связанных агрега-

тов, образующих сеть. В реляционной данные хранятся в виде

таблиц. В современных СУБД все более широкое применение нахо-

дит реляционная модель. В Турбо-Прологе эта модель реализует-

ся без каких-либо особых трудностей.

9.2.1. Файл базы данных

Файл базы данных представляет собой набор связанных меж-

ду собой записей. Файл БД имеет вид простого файла, однако

содержащиеся в нем данные имеют свою внутреннюю организацию.

Данные внутри каждой записи имеют одну и ту же структуру.

Часто имеется одна специальная запись, в которой записан спо-

соб представления данных в записях. Эта таблица (или схема)

играет роль "карты", руководствуясь которой программа СУБД

работает с этими данными.

В гл 7 было описано несколько способов работы с файлами,

включая создание файлов, запись в них данных, чтение и моди-

фикация уже имеющихся файлов. Все эти сведения будут полезны

при рассмотрении файлов БД.

Файл - это совокупность записей. В свою очередь запись -

это совокупность полей. Каждое поле содержит часть данных.

Данные из программы начисления зарплаты из гл.4 могут служить

для иллюстрации вышесказанного. Они могут быть организованы в

виде записей файла, как это показано на рис. 9.1.

Каждая запись содержит три поля, которые имеют имена

Name (имя), Department (отдел) и Rate (ставка). Содержимым

полей первой записи являются John Walker, ACCT и $3.5 . Такая

структура достаточно характерна для реляционных баз данных.

Базисные операции работы с файлами включают добавление

новых записей, модификацию старых и запросы к БД. Основываю-

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

данных позволяют использовать результаты запросов к базе в

качестве новых данных, которые можно поместить в БД в новых

записях.

Обычно все записи файла БД имеют одинаковую длину, поэ-

тому расположение любой записи в файле определяется без тру-

да. В базе данных на Турбо-Прологе, однако, требование одина-

ковости длин может и не соблюдаться, так как Турбо-Пролог

располагает записи в соответствии с шаблоном.

9.2.2. Реляционные базы данных

Как уже было сказано, данные в реляционных БД можно

представлять себе как элементы таблицы, состоящей из колонок

и строк (см. рис. 9.2).

Эта таблица состоит из трех колонок и пяти строк. Верх-

нее имя player является названием таблицы, всей структуры

данных. player есть отношение. Имя колонки задает имя атрибу-

та, который связан в таблице с другими атрибутами. Для отно-

шения player введены три атрибута. Набор атрибутов, в данном

случае атрибутов Name, Team и Position, называется реляцион-

ной схемой. Количество колонок (атрибутов) называется ар-

ностью отношения. Арность отношения player равна 3.

Строку таблицы в реляционной базе данных обычно называют

элементом отношения. В нашем примере первым элементом отноше-

ния является

Dan Marino, Miami Dolphins, QB

Число элементов отношения называется мощностью отноше-

ния. Мощность отношения player равна 5.

Приведенные термины составляют необходимую для разгово-

ра о системах управления реляционных БД терминологию. Эта ос-

нова будет полезна при дальнейшем обсуждении динамических баз

данных.

9.2.3. Базы данных в Турбо-Прологе

В Турбо-Прологе имеются специальные средства для органи-

зации баз данных. Эти средства рассчитаны на работу с реляци-

онными базами данных, так как Турбо-Пролог особенно хорош для

написания диалоговой системы именно для реляционной БД: внут-

ренние унификационные процедуры языка осуществляют автомати-

ческую выборку фактов с нужными значениями известных парамет-

ров и присваивают значения еще не определенным. К тому же

механизм отката позволяет находить все имеющиеся ответы на

сделанный запрос. В следующих разделах мы покажем, как ис-

пользовать Турбо-Пролог при проектировании и создании двух

программ БД.

Сравнивая рис. 9.2 и 9.3, можно заметить сходство между

стандартной реляционной базой данных и базой данных на Тур-

бо-Прологе.

Чтобы понять, как в Турбо-Прологе реализуется обращение

к БД, рассмотрим запрос

dplayer("Bernie Kosar",Team,Pos).

В этом утверждении Team и Pоs есть переменные, значения кото-

рых нужно найти. Когда этот запрос (цель) испытывается, про-

цедуры Турбо-Пролога просматривают утверждения БД на предмет

сопоставления с утверждением, содержащим Bernie Kosar. Так

как в базе данных такое утверждение присутствует, то перемен-

ной Team присваивается значение Cleveland Browns, а перемен-

ной Pos - QB.

Если трактовать dplayer как предикат БД Турбо-Пролог,

то отсюда следует с необходимостью такое его описание

database

dplayer(name,team,position)

Раздел database в Турбо-Прологе предназначен для описа-

ния предикатов базы данных, таких как dplayer. Все различные

утверждения этого предиката составляют динамическую базу дан-

ных Турбо-Пролога. База данных называется динамической, так

во время работы программы из нее можно удалять любые содержа-

щиеся в ней утверждения, а также добавлять новые. В этом сос-

тоит ее отличие от "статических" баз данных, где утверждения

являются частью кода программы и не могут быть изменены во

время счета. Другая важная особенность динамической базы дан-

ных состоит в том, что такая база может быть записана на

диск, а также считана с диска в оперативную память.

Иногда бывает предпочтительно иметь часть информации ба-

зы данных в виде утверждений статической БД; эти данные зано-

сятся в динамическую БД сразу после активизации програм-

мы.(Для этой цели используются предикаты asserta и assertz,

которые будут рассмотрены ниже.) В общем, предикаты статичес-

кой БД имеют другое имя, но ту же самую форму представления

данных, что и предикаты динамической. Предикат статической

БД, соответствующий предикату dplayer динамической базы дан-

ных, есть

predicates

player(name,team,position)

clauses

player("Dan Marino","Miami Dolphins","QB").

player("Richart Dent","Chicago Bears","DE").

player("Bernie Kosar","Cleveland Browns","QB").

player("Doug Cosbie","Dallas Cowboy","TE").

player("Mark Malone","Pittsburgh Steelers","QB").

Заметим, что все отличие предиката dplayer по сравнению

с player заключается лишь в одной лишней букве терма. Добав-

ление латинской буквы d - обычный способ различать предикаты

динамической и статической баз данных.

Правилом для занесения в динамическую БД информации из

утверждений предиката player служит

assert_database :-

player(Name,Team,Number),

assertz( dplayer(Name,Team,Number) ),

fail.

assert_database :- !.

В этом правиле применяется уже знакомый вам метод отката пос-

ле неудачи, который позволяет перебрать все утверждения пре-

диката player. Метод ОПН обсуждался в гл.4.

Сравнивая данный пример с отношением базы данных на рис.

9.1, можно указать следующее соответствие понятий:

База данных Турбо-Пролога Реляционная база данных

предикат БД отношение

объект атрибут

отдельное утверждение элемент отношения

количество утверждений мощность

Теперь, после проведения сравнения понятий, введенная

ранее терминология Турбо-Пролога приобретает новое значение,

поскольку она прилагается к реляционным базам данных. Поэтому

следует еще раз уяснить себе смысл таких уже встречавшихся

терминов, как предикат, объект, утверждение, арность, чтобы

можно было освоиться с новыми их приложениями.

Именно с таких позиций мы будем использовать в дальней-

шем при описании БД терминологию Турбо-Пролога. Конечно, мож-

но было бы использовать и такие традиционные понятия как от-

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

в данном контексте.

9.2.4. Предикаты динамической базы данных в Турбо-Прологе

При создании динамической базы данных Турбо-Пролога бу-

дут очень полезны многие уже известные вам вещи. Так, здесь

применим почти весь материал, касающийся предикатов и утверж-

дений Турбо-Пролога, рассмотренный в гл.2 и 3. Можно созда-

вать правила для работы с информацией БД, можно также исполь-

зовать введенные в гл.7 предикаты, осуществляющие обращение к

файлам, файлам БД, записанным на диск.

В Турбо-Прологе имеются и специальные встроенные преди-

каты для работы с динамической базой данных. Таковыми являют-

ся asserta, assertz, retract, save, consult, readterm и

findall. В следующем разделе мы опишем эти предикаты и пока-

жем, как нужно их использовать.

* Предикаты для работы с утверждениями динамической базы дан-

ных

Предикаты asserta, assertz и retract позволяют занести

факт в заданное место динамической БД и удалить из нее уже

имеющийся факт.

Предикат asserta заносит новый факт в базу данных, рас-

полагающуюся в оперативной памяти компьютера (резидентная

БД). Новый факт помещается перед всеми уже внесенными утверж-

дениями данного предиката. Этот предикат имеет такой синтак-

сис:

asserta(Clause).

Таким образом, чтобы поместить в БД утверждение

dplayer("Bernie Kosar","Cleveland Browns","QB").

перед уже имеющимся там утверждением

dplayer("Doug Cosbie","Dallas Cowboy","TE").

( стоящим в настоящий момент в базе данных на первом месте),

необходимо следующее предикатное выражение

asserta(dplayer("Bernie Kosar","Cleveland Browns","QB")).

Теперь БД содержит два утверждения, причем утверждение

со сведениями о Kosar предшествует утверждению со сведениями

о Cosbie:

dplayer("Bernie Kosar","Cleveland Browns","QB").

dplayer("Doug Cosbie","Dallas Cowboy","TE").

Крайне важно отдавать себе отчет в том, что в динамичес-

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

В этом состоит отличие Турбо-Пролога от других реализаций

языка Пролог.

Предикат assertz так же, как и asserta, заносит новые

утверждения в базу данных. Однако он помещает новое утвержде-

ние за всеми уже имеющимися в базе утверждениями того же пре-

диката. Синтаксис предиката столь же прост:

assertz(Clause).

Для добаления к двум уже имеющимся в БД утверждениям

третьего

dplayer("Mark Malone","Pittsburgh Steelers","QB").

требуется следующее предикатное выражение:

assertz(dplayer("Mark Malone","Pittsburgh Steelers","QB")).

после чего БД будет содержать третеего утверждения

dplayer("Bernie Kosar","Cleveland Browns","QB").

dplayer("Doug Cosbie","Dallas Cowboy","TE").

dplayer("Mark Malone","Pittsburgh Steelers","QB").

Третье, новое, только что занесенное утверждение, следу-

ет за двумя старыми.

Предикат retract удаляет утверждение из динамической БД

(еще раз напомним, что динамическая БД содержит факты, но не

правила.) Его синтаксис таков:

retract(Existing_clause).

Предположим, что вы хотите удалить из базы данных второе

утверждение. Для этого необходимо написать выражение

retract(dplayer("Doug Cosbie","Dallas Cowboy","TE")).

и БД будет состоять уже только из двух утверждений:

dplayer("Bernie Kosar","Cleveland Browns","QB").

dplayer("Mark Malone","Pittsburgh Steelers","QB").

Так же, как asserta и assertz, retract применим только

в отношении фактов.

Для модификации базы данных можно использовать комбина-

цию выражений с предикатами asserta, assertz и retract. Нап-

ример, для того, чтобы отредактировать содержащееся в БД ут-

верждение, ваша программа должна получить данные от

пользователя, составить новое утверждение, удалить старое и

занести новое.

* Предикаты для работы с базой данных в целом

В данном разделе будут описаны предикаты для работы с БД

в целом. Предикаты save и consult применяются для записи ди-

намической БД в файл на диск и для загрузки содержимого файла

в динамическую БД.

Предикат save cохраняет находящуюся в оперативной памяти

базу данных в текстовом файле. Синтаксис этого предиката

save(DOS_file_name).

где DOS_file_name есть произвольное допустимое в MS DOS или

PC DOS имя файла. (Если вы не знакомы с требованиями к именам

файлов, обратитесь к Приложению С настоящей книги.)

Для того, чтобы сохранить содержимое футбольной БД в

файле с именем football.dba, требуется предикат

save("football.dba").

В результате все утверждения находящейся в оперативной

памяти динамической БД будут записаны в файл football.dba.

Если файл с таким именем уже имелся на диске, то этот старый

файл будет затерт. Следует поэтому использовать предикат save

с известной долей осторожности.

Файл БД может быть считан в память (загружен) при помощи

предиката consult, систаксис которого таков:

consult(DOS_file_name).

Для загрузки файла футбольной БД требуется выражение

consult("football.dba").

Предикат consult неуспешен, если файл с указанным именем

отсутствует на диске, или если этот файл содержит ошибки,

как, например, в случае несоответствия синтаксиса предиката

из файла описаниям из раздела программы database, или если

содержимое файла невозможно разместить в памяти ввиду отсутс-

твия места.

Предикат readterm используется для чтения из файла объ-

ектов, относящихся к определенному в программе домену. Син-

таксис этого предиката

readterm(Domain,Term).

где Domain задает имя домена, а Term - различные наборы зна-

чений объектов этого домена. Рассмотрим, к примеру, преди-

катное выражение

readterm(auto_record,auto(Name,Year,Price)).

В этом выражении Domain замещен на auto_record, Term -

на auto(Name,Year,Price). Терм auto определяет все наборы

значений этого домена.

Необходимое описание доменов должно выглядеть так:

domains

name = string

year = integer

price = real

auto_record = auto(name,year,price)

file = auto_file

Предикат readterm обычно используется для считывания с

диска данных, записанных в форме утверждений. Так в нашем

случае, например, в файле могут находиться такие строки:

auto("Pontiac",1984,8550)

auto("Chevrolet",1982,2300)

auto("Chevette",1982,1500)

auto("Toyota",1986,11000)

Для получения доступа к файлу сначала необходимо вос-

пользоваться предикатами openread и readdevice, после чего

можно применить readterm.

В нашем примере предикат readterm пытается сопоставить

auto с cоответствующими утверждениями из файла. Если преди-

кат успешен, переменные Name, Year и Price получают значения

из соответствующего утверждения. Эти значения можно вывести

на экран видео или же на любое другое выводное устройство.

* Упраженение

9.1. Напишите программу для вывода данных об автомобилях из

только что разобранного примера. Для создания файла данных

воспользуйтесь редактором Турбо-Пролога.

Предикат findall позволяет собрать все имеющиеся в базе

данные в список, который может быть полезен при дальнейшей

работе. (Предикат findall был описан в гл.5.) Так, findall

можно использовать для получения списка имен всех игроков.

После того, как успешным будет предикат

findall(Name,dplayer(Name,_,_),Name_list)

переменная Name_list содержит список имен всех игроков.

9.3. Создание базы данных, располагающейся в оперативной па-

мяти

Процесс создания базы данных в Турбо-Прологе начинается

с этапа проектирования базы. При этом требуется учесть сле-

дующие факторы:

1) размер базы данных ;

2) организацию элементов базы данных ;

3) способы работы и содержания базы данных .

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

памяти (резидентных), вполне оправданно, если эта БД имеет не

слишком большой объем.

Для начала необходимо задать начальные данные и создать

саму базу. Затем наступает черед системы управления базой

данных (СУБД), ориентированной на диалог с пользователем. Лю-

бая система такого рода должна содержать как минимум такие

возможности:

1) занесение в базу новых данных ;

2) удаление данных из базы ;

3) выборка и вывод содержащихся в базе данных.

Вполне естественно, что эти возможности хотелось бы реа-

лизовать достаточно логичным способом, и так, чтобы они были

удобны для пользователя. Эти требования предполагают наличие

в системе меню, представляющее пользователю возможность легко

ориентироваться при обращениии к стандартными функциям СУБД,

а также оконной системы, дающей четкое представление о дос-

тупных пользователю средствах.

9.3.1. Обсуждение проекта базы данных

Лучший способ начать проектирование программы - это на-

рисовать ее диаграмму потоков данных, как это сделано на рис.

9.4. Стрелки на этой диаграмме показывают порядок передачи

управления и поток данных в программе. Стрелки одного типа

обозначают перемещение данных от одного модуля программы к

другому, а стрелки другого типа - порядок вызова этих модулей

в процессе работы при выполнении некоторого задания.

Рассмотрим операцию записи в базу новых данных. Пользо-

ватель, сидящий за клавиатурой, запускает программу на счет.

Для записи новых данных выбирается опция Add. Управление та-

ким образом передается от основного модуля do_mbase к модулю

menu, а затем к process(1). Так ввод осуществляется с клавиа-

туры, то именно от нее и берет начало поток данных; далее он

идет к process(1) и оканчивается на мониторе и базе данных.

На диаграмме с рис. 9.4 программные модули выстроены в

иерархическую структуру. Управление потоком данных зависит от

выбора команды пользователем. Структурная схема, соответству-

ющая данной ДПД, приведена на рис. 9.5. Она показывает, что

модуль menu позволяет пользователю выбрать между четырьмя мо-

дулями: process(1) для записи данных в базу, process(2) для

удаления данных, process(3) для высвечивания данных на мони-

торе, и process(4) для выхода из системы.

9.3.2. Создание базы данных

Проект, намеченный при помощи ДПД и СС, может служить

руководством для написания программы БД на Турбо-Прологе.

Данные представляют собой информацию о пяти профессиональных

футболистах. Они включают имена игроков, названия их команд,

номера, позиции, рост, вес, количество сыгранных в NFL (Наци-

ональная футбольная лига) сезонов, а также название универси-

тета, за который выступал данный игрок до ухода в профессио-

налы. Вся используемая информация приведена в табл. 9.1.

Таблица 9.1. Данные об игроках

_____________________________________________________________

Имя Команда N Поз.Рост Вес С Университет

Dan Marino Miami Dolphins 13 QB 6'3'' 215 4 Pittsburgh

Richart Dent Chicago Bears 95 DE 6'5'' 263 4 Tenn.State

Bernie Kosar Cleveland Browns 19 QB 6'5'' 210 2 Miami

Doug Cosbie Dallas Cowboys 84 TE 6'6'' 235 8 Santa Clara

Mark Malone Pittsburgh Steelers 16 QB 6'4'' 223 7 Arizona State

______________________________________________________________

Для работы с ней необходим предикат, кодирующий эту ин-

формацию. Подходящим является

player(p_name, /* полное имя игрока (string) */

t_name, /* название команды (string) */

p_number, /* номер игрока (integer) */

pos, /* позиция игрока (string) */

height, /* рост (string) */

weight, /* вес (string) */

nfl_exp, /* стаж выступлений (integer) */

college) /* университет (string) */

Объектам предиката присвоены имена, поясняющие суть де-

ла, и поэтому легко запоминаемые. Объект p_name кодирует имя

игрока, t_name - название команды и т.д. Этот предикат явля-

ется основой для дальнейшего построения базы данных.

Турбо-Пролог требует, чтобы все утверждения одного и

того же предиката были сгруппированы в одном месте. В соот-

ветствии с этим требованием группа предиката player записы-

вается в виде:

player("Dan Marino","Miami Dolphins",13,"QB",

"6-3",215,4,"Pittsburgh").

player("Richart Dent","Chicago Bears",95,"DE",

"6-5",263,4,"Tennessee State").

player("Bernie Kosar","Cleveland Browns",19,"QB",

"6-5",210,2,"Miami").

player("Doug Cosbie","Dallas Cowboy",84,"TE",

"6-6",235,8,"Santa Clara").

player("Mark Malone","Pittsburgh Steelers",16,"QB",

"6-4",223,7,"Arizona State").

Заметим, что в том случае, когда объекты утверждений яв-

ляются строками и начинаются с заглавных букв, они заключают-

ся в кавычки. Также отметим, что рост игрока задается в виде

строки, хотя он и подразумевает числовое значение; в БД как

число он не используется.

Следующей фазой создания БД является задание соответст-

вующих описаний типов. Раздел нашей программы domains будет

выглядеть так:

domains

p_name, t_name, pos, height, college = string

p_number, weight, nfl_exp = integer

Конечно, если вы создаете свою собственную базу данных,

вам могут потребоваться и объекты типа symbol или real. Их

необходимо также описать в разделе domains.

Предикаты динамической базы данных описываются в разде-

ле программы database. В нашем случае необходим лишь один

такой предикат:

database

dplayer(p_name, t_name, p_number, pos,

height, weight, nfl_exp, college)

Когда программа запускается на счет, утверждения дина-

мической БД помещаются в оперативной памяти отдельно от

"обычных" утверждений. (Это одна из причин того, что преди-

каты динамической БД описываются в специальном разделе прог-

раммы.) В этот момент БД полностью готова к работе.

В разделе predicates следует описать все другие преди-

каты, используемые в программе. Эти описания выглядят так:

predicates

repeat /* повтор */

do_mbase /* цель */

assert_database /* создание БД */

menu /* интерфейс в виде меню */

process(integer) /* различные операции из перечня меню */

clear_database /* очистка БД */

player(p_name, t_name, p_number, pos,

height, weight, nfl_exp, college)

error /* выдача сообщения об ошибке */

Как уже ранее говорилось, в начале работы программы не-

обходимо занести в динамическую БД предназначенную для нее

информацию, содержащуюся в статической БД. Эту задачу выпол-

няет предикат assert_database. Предикат clear_database пред-

назначен для решения смежной задачи: очиски БД перед оконча-

нием работы программы. На самом деле, конечно, эта работа

является лишней, но мы включили этот предикат в нашу програм-

му, так как очиска БД бывает нужна в некоторых приложениях.

Назначение и функции предиката repeat разбирались в гл.

4. Задачей предиката error является реагирование на ввод неп-

равильной входной информации.

Предикат player предназначен для задания начального со-

держимого базы данных, той информации, которая отражена в

табл. 9.1. Когда программа начинает работу, эта информация

засылается в утверждения предиката dplayer.

Предикат do_mbase является главным правилом (модулем)

программы. Он также присутствует в целевом утверждении. Пре-

дикат menu определяет правило, осуществляющее интерфейс с

пользователем при помощи меню. Предикат process(integer) оп-

ределяет различные правила, выполняющие все возможные опера-

ции над БД.

Раздел программы goal содержит правило do_mbase:

goal

do_mbase.

Теперь можно обобщить все сказанное выше и определить

"скелет" нашей программы БД. Тела правил будут определены в

разделе программы в разделе программы clauses.

9.3.3 Написание программных модулей

После завершения стадии проектирования можно приступить

к стадии реализации проекта. Теперь нашей задачей явится

написание предикатных выражений и вспомогательных правил,

которые потребуются основным модулям.

* Главный модуль

Главный модуль программы do_mbase является одновременно

и целью программы:

do_mbase :-

assert_database,

makewindow(1,7,7," PRO FOOTBALL DATABASE ",0,0,25,80),

menu,

clear_database.

Модуль засылает в базу информацию из утверждений player,

создает окно, высвечивает меню и очищает БД по окончании ра-

боты программы.

Исходное содержимое БД задается при помощи утверждений

с использованием статических предикатов. Правилом для зане-

сения в базу этой информации служит

assert_database :-

player(P_name,T_name,P_number,Pos,Ht,Wt,Exp,

College),

assertz( dplayer(P_name,T_name,P_number,Pos,Ht,

Wt,Exp,College) ),

fail.

assert_database :- !.

Этот предикат использует метод отката после неудачи

(ОПН), в том виде, как он был описан в гл. 4, для перебора

всех утверждений player.

Предикат очистки базы данных - это

clear_database :-

retract( dplayer(_,_,_,_,_,_,_,_) ),

fail.

clear_database :- !.

Так как объекты утверждений dplayer в этом правиле не

представляют интереса , то используются анонимные переменные.

Меню предназначено для удобства пользователя в выборе

программных функций. Для обеспечения отвечающего требованиям

экранного простанства создается окно на весь экран (25 строк,

80 колонок). Если вы хотите освежить в памяти детали создания

окон и выбора палитры, следует обратиться к гл.8. Модуль menu

высвечивет четыре доступные пользователю опции. Как уже было

сказано при обсуждении проекта программы, таковыми являются

1. Add a player to database (занесение в БД новой информа-

ции об игроках),

2. Delete a player from database (удаление об игроках из

БД),

3. View a player from database (выдача информации на эк-

ран),

4. Quit from this program (окончание работы с программой).

Модуль menu в основном состоит из предикатов write, ко-

торые высвечивают на экране перечисленные выше опции.

Звездочки используются здесь для выделения пространства, со-

держащего меню. В модуле присутствуют предикаты write, созда-

ющие этот бордюр из звездочек, и предикат, запрашивающий у

пользователя целое число в диапазоне от 1 до 4.

Модуль menu полностью соответствует предъявленным к не-

му в проекте программы требованиям:

menu :-

repeat,

clearwindow,

write(" * * * * * * * * * * * * * * * * * * * "),nl,

write(" * * "),nl,

write(" * 1. Add a player to database * "),nl,

write(" * 2. Delete a player from database * "),nl,

write(" * 3. View a player from database * "),nl,

write(" * 4. Quit from this program * "),nl,

write(" * * "),nl,

write(" * * * * * * * * * * * * * * * * * * * "),nl,

nl,

write(" Please enter your choice, 1, 2, 3 or 4 : "),

readint(Choice),nl,

process(Choice),

Choice = 4,

!.

Картинка экрана с меню приведена на рис. 9.6.

Обратим внимание на технику, использованную для обеспе-

чения повторных вызовов модуля menu. Если пользователь введет

число, не равное 4 (4 вызывает окончание программы), подцель

Choice = 4 становится неуспешной, что вызывает откат к преди-

кату repeat.

Правила process будут обсуждаться в следующих разделах.

* Модуль для ввода данных

Правило process(1) предназначено для занесения в базу

данных. Этот модуль создает окно для текста, просит пользова-

теля ввести данные с клавиатуры, считывает их и заносит в БД

новое утверждение dplayer. Вслед за этим модуль убирает вновь

созданное окно и возвращает управление главному меню.

Отдельное, меньшее по размеру окно создается для обеспе-

чения диалога с программой. За предикатом makewindow, создаю-

щим это окно, идут предикаты write, readln и readint, которые

информируют пользователя о том, какие данные он должен ввес-

ти, и считывают эти данные с клавиатуры:

process(1) :-

makewindow(2,7,7," Add Player to DATABASE ",

2,20,18,58),

shiftwindow(2),

write("Enter player name: "),

readln(P_name),

write("Enter team: "),

readln(T_name),

Аналогично при помощи write, readln и readint вводятся

номер игрока, его позиция, рост, вес, стаж выступлений и

университет. Пример взаимодействия с программой при вводе

данных можно видеть на рис. 9.7.

За предикатами write, readln и readint следует предикат

assertz. Этот предикат помещает новые утверждения dplayer

вслед за уже имеющимися.

Объектами этого нового утверждения являются значения,

присвоенные переменным P_name, T_name, P_number и т.п.; пе-

ременные означиваются в предикатах чтения.

assertz(dplayer(P_name,T_name,P_number,Pos,Ht,Wt,

Exp,College)),

write(P_name," has been added to the database."),

nl, !,

write("Press space bar. "),

readchar(_),

removewindow.

Последние строки сигнализируют об окончании процесса

ввода и убирают дополнительное окно.

* Модуль для удаления данных

Назначением модуля process(2) является удаление инфор-

мации из базы данных. Это правило, также как и правило

process(1), создает свое собственное окно, запрашивает у

пользователя имя игрока и удаляет из БД утверждение, содер-

жащее информацию об этом игроке. После очистки окна управле-

ние вновь передается главному меню.

Вслед за предикатами, создающими окно и сдвигающими его,

идут предикаты, запрашивающие имя игрока. Введенное пользова-

телем значение присваивается переменной P_name:

process(2) :-

makewindow(3,7,7," Delete Player from DATABASE ",

10,30,7,40),

shiftwindow(3),

write("Enter name to DELETE: "),

readln(P_name),

Следующая часть правила осуществляет операцию удаления

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

зователю, ждет нажатия им произвольной клавиши и убирает с

экрана дополнительное окно.

retract(dplayer(P_name,_,_,_,_,_,_,_)),

write(P_name," has been deleted from the database."),

nl, !,

write("Press space bar."),

readchar(_),

removewindow.

Для удаления из базы выбранного пользователем утвержде-

ния применен предикат retract. Так как любая другая информа-

ция об игроке, кроме его имени, не представляет интерес в

данной операции, то на месте всех других объектов стоят ано-

нимные переменные.

* Модуль для выборки данных

Назначением модуля process(3) является поиск содержа-

щихся в базе данных. Этот модуль, как и два уже разобранных,

создает свое собственное окно, а затем запрашивает имя игро-

ка. Если в БД находится утверждение, содержащее введенное

имя, модуль производит выборку данных и выводит их на экран

в удобном формате.

process(3) :-

makewindow(4,7,7," View Window ",

7,30,16,47),

shiftwindow(4),

write("Enter name to view: "),

readln(P_name),

dplayer(P_name,T_name,P_number,

Pos,Ht,Wt,Exp,College),

Предикат dplayer ищет нужное утверждение в базе данных

и выбирает строковые и целые значения по каждому запрашивае-

мому пункту. Целый ряд предикатов write затем выводит полу-

ченные значения:

nl, write(" NFL League Player"),nl,

nl, write(" Player Name : ",P_name),

nl, write(" Team Name : ",T_name),

nl, write(" Position : ",Pos),

nl, write(" Player Number : ",P_number),

nl, write(" Player's Height : ",Ht," ft-in"),

nl, write(" Player's Weight : ",Wt," lb "),

nl, write(" Player's NFL-exp : ",Exp," year(s)"),

nl, write(" Player's College : ",College),

nl, nl, !,

nl, write("Press space bar"),

readchar(_),

removewindow.

На рис. 9.8 приведена выдача данного модуля.

Если в БД отсутствует утверждение с введенным пользова-

телем именем игрока, программа выдает сообщение об ошибке.

Окно для этого сообщения должно располагаться на видном мес-

те, например, в центре экрана. Вариант process(3), отвечаю-

щий за выдачу сообщения об ошибке, выглядит так:

process(3) :-

makewindow(5,7,7," No Luck ",14,7,5,60),

shiftwindow(5),

write("Can't find that player in the database."),nl,

write("Sorry, bye!"),

nl, !,

write("Press space bar."),

readchar(_),

removewindow,

shiftwindow(1).

* Модуль окончания работы с программой

Модуль process(4) обеспечивает нормальное окончание се-

анса работы с базой данных. Этот модуль не создает своего

собственного окна. Новое окно здесь излишне, так как сообще-

ния очень коротки и не требуют много места на экране. Модуль,

однако, требует от пользователя четкого ответа на вопрос, хо-

чет ли он окончить работу с программой:

process(4) :-

write("Are you sure want to quit (y/n)"),

readln(Answer),

frontchar(Answer,'y',_), !.

Отметим для себя наличие в правиле предиката frontchar.

Он успешен только в том случае, если ответ пользователя на

запрос программы начинается с буквы Y. Если вводится иная

буква, предикат неуспешен, поэтому происходит откат к преди-

кату repeat модуля menu.

* Модуль реакции на ошибку

Аккуратно написанная программа должна надлежащим образом

реагировать на допущенные пользователем ошибки при вводе. Ес-

ли пользователь введет число, меньшее 1 или большее 4, будет

успешным одно из правил:

process(Choice) :-

Choice < 1,

error.

process(Choice) :-

Choice > 4,

error.

Оба эти правила вызывают модуль error:

error :-

write("Please enter a number from 1 to 4."),

write("(Press the space bar to continue)"),

readchar(_).

9.3.4. Футбольная база данных

Завершенной раализацией приведенного проекта динамичес-

кой базы данных является программа "Футбольная база данных" с

листинга 9.1.

_____________________________________________________________

Листинг 9.1

/* Программа: Футбольная база данных */

/* Файл: PROG0901.PRO */

/* */

/* Назначение: Демонстрация примера работающей базы */

/* данных. База данных допускает следую- */

/* дующие операции: добавление, удаление */

/* и выборку данных. Выборка включает */

/* просмотр данных. */

/* */

/* Замечание: Эта программа создает базу данных и */

/* содержит ее в оперативной памяти. */

domains

p_name, t_name, pos, height, college = string

p_number, weight, nfl_exp = integer

database

dplayer(p_name, t_name, p_number, pos,

height, weight, nfl_exp, college)

predicates

repeat

do_mbase

assert_database

menu

process(integer)

clear_database

player(p_name, t_name, p_number, pos,

height, weight, nfl_exp, college)

error

goal

do_mbase.

clauses

repeat.

repeat :- repeat.

/* Футбольная база данных */

player("Dan Marino","Miami Dolphins",13,"QB",

"6-3",215,4,"Pittsburgh").

player("Richart Dent","Chicago Bears",95,"DE",

"6-5",263,4,"Tennessee State").

player("Bernie Kosar","Cleveland Browns",19,"QB",

"6-5",210,2,"Miami").

player("Doug Cosbie","Dallas Cowboy",84,"TE",

"6-6",235,8,"Santa Clara").

player("Mark Malone","Pittsburgh Steelers",16,"QB",

"6-4",223,7,"Arizona State").

/* конец начальных данных */

assert_database :-

player(P_name,T_name,P_number,Pos,Ht,Wt,Exp,

College),

assertz( dplayer(P_name,T_name,P_number,Pos,Ht,

Wt,Exp,College) ),

fail.

assert_database :- !.

clear_database :-

retract( dplayer(_,_,_,_,_,_,_,_) ),

fail.

clear_database :- !.

/* Диалог с этой БД осуществляется по принципу меню.

При этом используются оконнные средства Турбо-Пролога.

Основываясь на запросе пользователя, СУБД активизирует

соотствующие процессы для удовлетворения этого запро-

са. Меню можно расширить за счет включения новых функ-

ций. */

/* задание цели в виде правила */

do_mbase :-

assert_database,

makewindow(1,7,7," PRO FOOTBALL DATABASE ",0,0,25,80),

menu,

clear_database.

menu :-

repeat,

clearwindow,

write(" * * * * * * * * * * * * * * * * * * * "),nl,

write(" * * "),nl,

write(" * 1. Add a player to database * "),nl,

write(" * 2. Delete a player from database * "),nl,

write(" * 3. View a player from database * "),nl,

write(" * 4. Quit from this program * "),nl,

write(" * * "),nl,

write(" * * * * * * * * * * * * * * * * * * * "),nl,

nl,

write(" Please enter your choice, 1, 2, 3 or 4 : "),

readint(Choice),nl,

process(Choice),

Choice = 4,

!.

/* Добавление информации об игроке в БД */

process(1) :-

makewindow(2,7,7," Add Player to DATABASE ",

2,20,18,58),

shiftwindow(2),

write("Enter player name: "),

readln(P_name),

write("Enter team: "),

readln(T_name),

write("Enter player number: "),

readint(P_number),

write("Enter position: "),

readln(Pos),

write("Enter height: "),

readln(Ht),

write("Enter weight: "),

readint(Wt),

write("Enter NFL exp: "),

readint(Exp),

write("Enter college: "),

readln(College),

assertz(dplayer(P_name,T_name,P_number,Pos,Ht,Wt,

Exp,College)),

write(P_name," has been added to the database."),

nl, !,

write("Press space bar. "),

readchar(_),

removewindow.

/* Удаление информации об игроке из БД */

process(2) :-

makewindow(3,7,7," Delete Player from DATABASE ",

10,30,7,40),

shiftwindow(3),

write("Enter name to DELETE: "),

readln(P_name),

retract(dplayer(P_name,_,_,_,_,_,_,_)),

write(P_name," has been deleted from the database."),

nl, !,

write("Press space bar."),

readchar(_),

removewindow.

/* Просмотр информации об игроке */

process(3) :-

makewindow(4,7,7," View Window ",

7,30,16,47),

shiftwindow(4),

write("Enter name to view: "),

readln(P_name),

dplayer(P_name,T_name,P_number,

Pos,Ht,Wt,Exp,College),

nl, write(" NFL League Player"),nl,

nl, write(" Player Name : ",P_name),

nl, write(" Team Name : ",T_name),

nl, write(" Position : ",Pos),

nl, write(" Player Number : ",P_number),

nl, write(" Player's Height : ",Ht," ft-in"),

nl, write(" Player's Weight : ",Wt," lb "),

nl, write(" Player's NFL-exp : ",Exp," year(s)"),

nl, write(" Player's College : ",College),

nl, nl, !,

nl, write("Press space bar"),

readchar(_),

removewindow.

process(3) :-

makewindow(5,7,7," No Luck ",14,7,5,60),

shiftwindow(5),

write("Can't find that player in the database."),nl,

write("Sorry, bye!"),

nl, !,

write("Press space bar."),

readchar(_),

removewindow,

shiftwindow(1).

/* Выход из диалога */

process(4) :-

write("Are you sure want to quit (y/n)"),

readln(Answer),

frontchar(Answer,'y',_), !.

/* Неправильное обращение к БД */

process(Choice) :-

Choice < 1,

error.

process(Choice) :-

Choice > 4,

error.

error :-

write("Please enter a number from 1 to 4."),

write("(Press the space bar to continue)"),

readchar(_).

/***** конец программы *****/

_____________________________________________________________

Каждый из фрагментов программы, спроектированный и опи-

санный в предыдущих разделах главы, занимает отведенное ему в

программе место. Отметим, что программа снабжена необходимым

минимумом комментариев, полезных программисту.

Исходная информация для БД помещается в начале раздела

clauses. Когда программа запускается на счет, подцель assert_

database создает утверждения dplayer, содержащие такие же

данные, что и утверждения статического предиката player, и

заносит эти утверждения в динамическую БД. После этого можно

добавлять, удалять или просматривать данные, выбирая соот-

ветствующие опции меню.

Искусная обработка большого числа запросов, наглядное

меню и выдача на экран, способность работать с большими

объемами данных - благодаря всему этому динамическая БД явля-

ется хорошей демонстрацией мощи Турбо-Пролога. Во второй час-

ти главы вы расширите свои познания в создании БД Турбо-Про-

лога, научившись работать с базами, располагающимися на

диске.

* Упражнения

9.2. Запустите на счет программу "Футбольная база данных".

Задайте опцию 1 главного меню и введите данные о каком-либо

футболисте. Затем выберите опцию 3 и введите имя того же иг-

рока. Теперь вы будете иметь возможность проверить правиль-

ность введенных в компьютер данных. Задайте опцию 2 и удалите

из базы данные о вашем игроке. Проверьте выполнение этой опе-

рации, снова задав опцию 3. Система должна выдать сообщение

об ошибке:

Can't find that player in the database.

(Информация об этом игроке отсутствует в БД.)

9.3. Измените прграмму "Футбольная база данных", добавив в

меню еще одну опцию:

5. List players in database

(Выдача списка всех игроков из БД)

Напишите модуль, который будет выполнять эту операцию.

Запустите измененный вариант программы и проверьте, справля-

ется ли он со своей задачей. Замечание: Используйте предикат

dplayer в форме

dplayer(Name,_,_,_,_,_,_,_).

а также воспользуйтесь методом отката после неудачи (ОПН).

9.4. Модифицируйте программу "Футбольная база данных" так,

чтобы БД сохранялась в файле на диске. Для этой цели исполь-

зуйте предикат

save("player.dat").

Вставьте этот предикат в подходящее место в программе

так, чтобы сохранение БД происходило в конце работы програм-

мы. Запустите программу на счет и проверьте правильность внес

енных изменений.

9.5. Внесите в программу такие изменения, чтобы можно было

выводить на экран лишь выборочную информацию об игроках. До-

бейтесь того, чтобы выдача на экран соответствовала вашим за-

мыслам.

9.4. Создание базы данных, располагающейся на диске

Из предыдущих разделов главы вы узнали, как проектиро-

вать и создавать системы управления базами данных, располага-

ющихся в оперативной памяти компьютера. Слабым местом всех

таких БД является то, что по мере накопления в ней новых дан-

ных сдерживающим фактором становится объем оперативной памяти

компьютера. Это ограничение, вероятно, будет весьма сущест-

венным в любом практическом приложении БД.

Более жизнеспособными являются СУБД, хранящие данные на

диске (нерезидентные). Так как объем внешней памяти сущест-

венно больше объема оперативной памяти, системы такого класса

пригодны для большинства практических задач.

Турбо-Пролог располагает всеми средствами, необходимыми

для поддержания таких значительных по объему информации БД.

Вероятно, пользователь по достоинству оценит возможности Тур-

бо-Пролога при работе с БД по мере увеличения объема его

собственной базы и усложнения программы.

9.4.1. Обсуждение проекта

Создание любой работающей с БД программы на Турбо-Проло-

ге начинается с обсуждения проекта базы данных. Так было при

рассмотрении резидентной БД.

Подобные рассуждения уместны и случае с БД на диске. Но-

вым здесь явятся правила для осуществления ввода и вывода ин-

формации, называемые обычно вводом-выводом на диск. В данном

случае программа нуждается в правилах чтения и записи внешних

файлов, поэтому следует еще раз повторить разд. 7.3, прежде

чем приступить к дальнейшему разговору о проекте БД.

Важной особенностью программы должно явиться обеспечение

эффективного доступа к базе. Это требование заставляет ис-

пользовать индексные файлы.

При разработке хранящейся на диске БД мы будем следовать

основным положениям, сформулированным для резидентных баз. Мы

также начнем проектирование с рисования диаграммы потоков

данных (рис. 9.9).

Структура этой диаграммы является расширением ДПД для

базы данных, располагающейся в оперативной памяти (смотри

рис. 9.4). Если сравнить две эти диаграммы, нетрудно увидеть,

что новая содержит дополнительно несколько модулей между

process и БД. Это вспомогательные модули, вызываемые модулями

process. Так, например, process(1) вызывает модуль dbassert,

который в свою очередь вызывает модуль dbass. Тонкие стрелки

на диаграмме показывают направление потока данных, а толстые

- порядок передачи управления.

Структурная схема программы приведена на рис. 9.10. Она

очень похожа на СС предыдущей программы (см. рис. 9.5).

Вспомогательные модули dbassert и dbass модуля

process(1) заносят в базу новые данные. Аналогичные структуры

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

на экран.

9.4.2. Создание базы данных

База данных "Университетский футбол" содержит информацию

о футбольных командах университетов. Характер информации и

соответствующие ей объекты Турбо-Пролога приведены в табл.

9.2. Изучив эту таблицу, вы будете в состоянии составить пре-

дикат для этих объектов.

Таблица 9.2. Информация, содержащаяся в БД "Университетский

футбол".

_____________________________________________________________

Информация Объект Турбо-Пролога Тип данных

Название команды name string

Название университета school string

Город city string

Штат state string

Цвета команды color string

Стадион stadium string

Имя тренера coach string

Год, за который при- year integer

ведены данные

Рейтинг team_power integer

Рейтинг нападения offensive_power integer

Рейтинг защиты defensive_power integer

Рейтинг воли к победе winning_power integer

Рейтинг своего поля home_power integer

____________________________________________________________

Заметим, что любая из выбранных характеристик вносит ка-

кую-то новую черту в представление о команде. При проектиро-

вании БД следует избегать включения в отношение излишней ин-

формации. Другими словами, если какой-либо параметр имеет

одно и то же значение для всех элементов отношения, то его

вряд ли стоит хранить в базе. Так, в нашу БД нет необходимос-

ти включать объект "вид спорта". Речь идет о футбольных ко-

мандах, и для каждого утверждения базы этот объект имел бы

значение football. Исключение из БД информации, общей для

всех отношений, называется нормализацией. Нормализация позво-

ляет экономить память и облегчает работу с правилами, осу-

ществляющими доступ к базе.

Данные в нашем примере требуют введения предиката такой

структуры:

team(name, school, city, state, color, stadium, coach,

year, team_power, offensive_power,

defensive_power, winning_power, home_power)

Предикат объявляется в разделе программы database. Не-

обходимо также описать (в разделе domains) объекты этого

предиката. В дополнение к ним нужно ввести два терма, обоз-

начающие файл БД и служебный индексный файл; о них разговор

шел несколько ранее. В результате раздел domains приобретает

следующий вид:

domains

file = datafile ;

indexfile

name, school, city, state, color,

stadium, coach = string

year,team_power, offensive_power,

defensive_power, winning_power, home_power = integer

Очередной стадией проектирования программы является

описание предикатов, осуществляющих различные операции над

базой, в разделе predicates. Из предыдущей программы данной

главы можно оставить предикаты:

do_dbase /* цель */

menu /* интерфейс в виде меню */

process /* различные операции из перечня меню */

Дополнительно к ним надо ввести вспомогательные модули,

ответственные за операции ввода-вывода: добавление, удаление

и вывод данных. Описание этих предикатов завершает разработ-

ку первой части программы БД на внешнем носителе. Полный

текст раздела predicates приведен ниже:

predicates

repeat

menu

process(integer)

do_dbase

dbassert(dbasedom) /* добавление данных */

dbass(dbasedom,string,string)

dbretract(dbasedom) /* удаление данных */

dbret(dbasedom,string,string)

dbret1(dbasedom,real)

dbread(dbasedom) /* чтение данных */

dbrd(dbasedom,string,string)

dbaaccess(dbasedom,real)

Модуль do_dbase является одновременно целью данной

программы. Теперь необходимо описать введенные правила в

разделе clauses.

Так же, как и предыдущая программа, do_dbase вызывает

модуль menu. В свою очередь menu вызывает один из модулей

process; который именно из них вызывается, зависит от значе-

ния введенного пользователем числа. Структура модулей

do_dbase и menu остается такой же, какой она была в программе

"Футбольная база данных". Модули process похожи на одноимен-

ные модули той же программы, с немногочисленными отличиями:

1) process(1) вызывает вспомогательный модуль dbassert,

предназначенный для засылки данных в базу на диск,

2) process(2) вызывает вспомогательный модуль dbretract,

который удаляет данные из базы на диске,

3) process(3) вызывает вспомогательный модуль dbread, осу-

ществляющий выборку данных для выдачи их на экран.

Эти вспомогательные модули имеют такие описания:

dbassert(Term) :-

dbass(Term,"cfootball.ind","cfootball.dba").

dbretract(Term) :-

dbret(Term,"cfootball.ind","cfootball.dba").

dbread(Term) :-

dbrd(Term,"cfootball.ind","cfootball.dba").

Каждое из трех правил вызывает свой модуль, выполняющий

заданную работу. Отметим, что в этих правилах содержатся

ссылки на файл БД и служебный индексный файл.

Ввод-вывод на диск осуществляется при помощи предикатов,

с которыми вы познакомились в гл.7. Для открытия файла БД

используется предикат openwrite. Используются также предикаты

writedevice, filepos и closefile.

* Модуль для ввода данных

Полностью модуль, отвечающий за ввод данных, выглядит

так:

dbass(Term,Indexfile,Datafile) :-

existfile(Indexfile),

existfile(Datafile),

openappend(datafile,Datafile),

writedevice(datafile),

filepos(datafile,Pos,0),

write(Term), nl,

closefile(datafile),

openappend(indexfile,Indexfile),

writedevice(indexfile),

writef("%7.0\n",Pos),

closefile(indexfile).

dbass(Term,Indexfile,Datafile) :-

openwrite(datafile,Datafile),

writedevice(datafile),

filepos(datafile,Pos,0),

write(Term), nl,

closefile(datafile),

openwrite(indexfile,Indexfile),

writedevice(indexfile),

writef("%7.0\n",Pos),

closefile(indexfile).

Обратим внимание на использование в правиле предиката

writef("%7.0\n",Pos),

Этот предикат предназначен для записи значения индекса,

задаваемого переменной Pos. Для записи индекса отводится по-

ле, состоящее из семи позиций. Значение, присвоенное перемен-

ной Pos, опеределяет положение записи в файле БД.

Первый вариант правила dbass предназначен для записи

данных в уже существующий файл. Оба варианта правила по су-

ществу идентичны, отличие состоит лишь в том, что первый ва-

риант использует предикат existfile, а также openappend вмес-

то openwrite.

На рис. 9.11 приведено состояние экрана после того, как

пользователь ввел данные об одной из университетских команд.

* Модуль для удаления данных

Модуль dbretract удаляет данные из БД. Он вызывает мо-

дуль dbret, который производит операцию удаления после отк-

рытия файла БД и индексного файла.

dbret(Term,Indexfile,Datafile) :-

openread(datafile,Datafile),

openmodify(indexfile,Indexfile),

dbret1(Term,-1),

closefile(datafile),

closefile(indexfile).

В правиле используется вспомогательный модуль dbret1,

который осуществляет поиск нужной записи и ее удаление:

dbret1(Term,Datpos) :-

Datpos >= 0,

filepos(datafile,Datpos,0),

readdevice(datafile),

readterm(Dbasedom,Term), !,

filepos(indexfile,-9,1),

flush(indexfile),

writedevice(indexfile),

writef("%7.0\n",-1),

readdevice(keyboard),

writedevice(screen).

Особое внимание следует обратить на предикат flush. Этот

предикат вызывает запись на диск содержимого внутреннего бу-

фера индексного файла. Таким образом dbret1 предотвращает

возможность работы с данными, которые уже были удалены до

этого.

Поиск нужного индекса в индексном файле осуществляет

следующий вариант dbret1:

dbret1(Term,_) :-

readdevice(indexfile),

readreal(Datpos1),

dbret1(Term,Datpos1).

* Модуль для выборки данных

Назначением модуля dbrd является поиск и чтение данных,

содержащихся в БД. Модуль оформлен следующим образом:

dbrd(Term,Indexfile,Datafile) :-

openread(datafile,Datafile),

openread(indexfile,Indexfile),

dbaaccess(Term,-1),

closefile(datafile),

closefile(indexfile).

Как видно из приведенного текста, здесь используется

вспомогательный модуль dbaaccess, осуществляющий поиск и вы-

борку данных из файла БД. Вариант правила, работающий с фай-

лом БД, задается таким выражением:

dbaaccess(Term,Datpos) :-

Datpos >= 0,

filepos(datafile,Datpos,0),

readdevice(datafile),

readterm(dbasedom,Term).

Этот предикат читает данные, логически связанные со зна-

чением индекса, задаваемым переменной Datapos. Соответствую-

щие значение индекса ищется в индексным файле другим вариан-

том dbaaccess:

dbaaccess(Term,_) :-

readdevice(indexfile),

readreal(Datpos1),

dbaaccess(Term,Datpos1).

Это правило пытается найти в базе такую запись, индекс

которой присутствует в индексном файле. Если индекс находит-

ся, по правило успешно; если нет, то неуспешно. В случае ус-

пеха переменная Term получает нужные пользователю значения.

Выдача программы при запросе сведений об университетской

футбольной команде приведена на рисунке 9.12. Данные выводят-

ся в удобном для чтения формате.

9.4.3. Программа базы данных "Университетский футбол"

Программа "Университетский футбол" (листинг 9.2) реали-

зует предложенный в предыдущих разделах проект базы данных.

______________________________________________________________

Листинг 9.2

/* Программа: Университетский футбол. */

/* Файл: PROG0902.PRO */

/* */

/* Назначение: Демонстрация примера работающей базы */

/* данных, содержащей сведения о футболь-*/

/* ных командах. База данных допускает */

/* следующие операции: добавление, удале-*/

/* ние и выборку данных. Выборка */

/* включает просмотр данных. */

/* */

/* Замечание: Эта программа создает базу данных и */

/* размещает на диске индексный файл. */

/* Имя этого файла - CFOOTBALL.DBA, имя */

/* связанного индексного файла - */

/* CFOOTBALL.IND. Файлы располагаются в */

/* текущей директории. */

domains

file = datafile ;

indexfile

name, school, city, state, color,

stadium, coach = string

year,team_power, offensive_power,

defensive_power, winning_power, home_power = integer

database

team(name, school, city, state, color, stadium, coach,

year, team_power, offensive_power,

defensive_power, winning_power, home_power)

predicates

repeat

menu

process(integer)

do_dbase

dbassert(dbasedom)

dbass(dbasedom,string,string)

dbretract(dbasedom)

dbret(dbasedom,string,string)

dbret1(dbasedom,real)

dbread(dbasedom)

dbrd(dbasedom,string,string)

dbaaccess(dbasedom,real)

goal

do_dbase.

clauses

/* Диалог с этой БД осуществляется по принципу меню.

При этом используются оконные средства Турбо-Пролога.

Основываясь на запросе пользователя, СУБД активизирует

соответствующие процессы для удовлетворения этого зап-

роса. */

/* задание цели в виде правила */

do_dbase :-

makewindow(1,7,7," COLLEGE FOOTBALL DATABASE ",

0,0,24,80),

menu.

menu :-

repeat,

clearwindow,

nl,

write(" * * * * * * * * * * * * * * * * * * * "),nl,

write(" * * "),nl,

write(" * 1. Add a player to database * "),nl,

write(" * 2. Delete a player from database * "),nl,

write(" * 3. View a player from database * "),nl,

write(" * 4. Quit from this program * "),nl,

write(" * * "),nl,

write(" * * * * * * * * * * * * * * * * * * * "),nl,

nl,

write(" Please enter your choice, 1, 2, 3 or 4 : "),

readint(Choice),nl,

Choice > 0, Choice < 5,

process(Choice),

Choice = 4,

!.

/* Добавление информации о команде в БД */

process(1) :-

makewindow(2,7,7," Add a Team to DATABASE ",

2,20,18,58),

shiftwindow(2),

write("Enter team's nickname: "),

readln(Name),

write("Enter school: "),

readln(School),

write("Enter city: "),

readln(City),

write("Enter state: "),

readln(State),

write("Enter color: "),

readln(Color),

write("Enter stadium: "),

readln(Stadium),

write("Enter coach's name: "),

readln(Coach),

write("Enter year: "),

readint(Year),

write("Enter team power: "),

readint(TMP),

write("Enter offensive power: "),

readint(OFP),

write("Enter defensive power: "),

readint(DEP),

write("Enter winning power: "),

readint(WNP),

write("Enter home power: "),

readint(HMP),nl,

dbassert(team(Name,School,City,State,Color,Stadium,

Coach,Year,TMP,OFP,DEP,WNP,HMP)),

write(Name," has been added to the database."),

nl, !,

write("Press space bar. "),

readchar(_),

removewindow,

shiftwindow(1).

/* Удаление информации о команде из БД */

process(2) :-

makewindow(3,7,7," Delete а Team from DATABASE ",

10,30,7,40),

shiftwindow(3),

write("Enter name to DELETE: "),

readln(Name),

dbretract(team(Name,_,_,_,_,_,_,_,_,_,_,_,_)),

write(Name," has been deleted from the database."),

nl, !,

write("Press space bar."),

readchar(_),

removewindow,

shiftwindow(1).

/* Просмотр информации о команде */

process(3) :-

makewindow(4,7,7," View а Team ",

6,18,17,58),

shiftwindow(4),

write("Enter the team's nickname: "),

readln(Name),

dbread(team(Name,School,City,State,Color,Stadium,

Coach,Year,TMP,OFP,DEP,WNP,HMP)),nl,

write(" ",Name),nl,

write(" ",School," ",City," ",State),nl,

write(" ",Color," ",Stadium," ",Coach),nl,nl,

write(" ",Year),nl,nl,

write(" Team Power = ",TMP),nl,

write(" Offensive Power = ",OFP),nl,

write(" Defensive Power = ",DEP),nl,

write(" Winning Power = ",WNP),nl,

write(" Home Power = ",HMP),nl, !,

write("Press space bar"),

readchar(_),

removewindow,

shiftwindow(1).

process(3) :-

makewindow(5,7,7," Message Window ",14,7,5,50),

shiftwindow(5),

write("Can't find that team in the database."),nl,

write("Sorry, bye!"),

closefile(datafile),

closefile(indexfile), nl, !,

write("Press space bar."),

readchar(_),

removewindow,

shiftwindow(1).

/* Выход из диалога */

process(4) :-

write("You are now exiting the 'College"),

write(" Football Database' program."),nl,

write(" Please press the space bar."),

readchar(_),

exit.

repeat. repeat :- repeat.

/* Правила для работы с БД */

dbassert(Term) :-

dbass(Term,"cfootball.ind","cfootball.dba").

dbretract(Term) :-

dbret(Term,"cfootball.ind","cfootball.dba").

dbread(Term) :-

dbrd(Term,"cfootball.ind","cfootball.dba").

/* Правило dbass записывает информацию в файл datafile

и модифицирует файл indexfile */

dbass(Term,Indexfile,Datafile) :-

existfile(Indexfile),

existfile(Datafile),

openappend(datafile,Datafile),

writedevice(datafile),

filepos(datafile,Pos,0),

write(Term), nl,

closefile(datafile),

openappend(indexfile,Indexfile),

writedevice(indexfile),

writef("%7.0\n",Pos),

closefile(indexfile).

dbass(Term,Indexfile,Datafile) :-

openwrite(datafile,Datafile),

writedevice(datafile),

filepos(datafile,Pos,0),

write(Term), nl,

closefile(datafile),

openwrite(indexfile,Indexfile),

writedevice(indexfile),

writef("%7.0\n",Pos),

closefile(indexfile).

/* Правило dbret удаляет данные из БД */

dbret(Term,Indexfile,Datafile) :-

openread(datafile,Datafile),

openmodify(indexfile,Indexfile),

dbret1(Term,-1),

closefile(datafile),

closefile(indexfile).

dbret1(Term,Datpos) :-

Datpos >= 0,

filepos(datafile,Datpos,0),

readdevice(datafile),

readterm(Dbasedom,Term), !,

filepos(indexfile,-9,1),

flush(indexfile),

writedevice(indexfile),

writef("%7.0\n",-1),

readdevice(keyboard),

writedevice(screen).

dbret1(Term,_) :-

readdevice(indexfile),

readreal(Datpos1),

dbret1(Term,Datpos1).

/* Правило dbrd извлекает информацию из файла

datafile */

dbrd(Term,Indexfile,Datafile) :-

openread(datafile,Datafile),

openread(indexfile,Indexfile),

dbaaccess(Term,-1),

closefile(datafile),

closefile(indexfile).

dbaaccess(Term,Datpos) :-

Datpos >= 0,

filepos(datafile,Datpos,0),

readdevice(datafile),

readterm(dbasedom,Term).

dbaaccess(Term,_) :-

readdevice(indexfile),

readreal(Datpos1),

dbaaccess(Term,Datpos1).

/***** конец программы *****/

__________________________________________________

Программа содержит некоторое количество комментариев,

которые информируют о том, что она делает. Одновременно пояс-

няется назначение различных программных модулей.

Приведенная программа, в отличие от программы "Футболь-

ная база данных", первоначально создает пустую БД. Для того,

чтобы в БД появилась какая-либо информация, необходимо выб-

рать опцию Add a team to database главного меню для записи на

диск новых данных. После ввода данных можно задать опцию View

a team from the database и просмотреть данные на экране дисп-

лея. Таким способом в БД можно записать столько данных,

сколько есть свободного места на диске. Так, можно ввести в

базу названия и показатели лучших футбольных команд. "Оживле-

ние" БД реальной информацией обычно делает работу с ней более

интересной.

* Упражнения

9.6. Запустите на счет программу "Университетский футбол".

Выберите в меню опцию Add a team to database и введите инфор-

мацию о нескольких командах. Вслед за этим выберите опцию

View a team from database и выведите на экран сведения о не-

которых из них.

9.7. Задайте опцию меню Delete a team from database и удалите

из базы данные о части команд. Задайте далее опцию View a

team from database и введите название одной из только что

удаленных команд. Убедитесь в том, что программа реагирует на

ваши действия выдачей сообщения об отсутствии в БД команды с

таким названием.

9.8. Модифицируйте программу, дополнив меню опцией Display

names of teams (Просмотр названий команд). Добавьте в текст

программы правила, реализующие новую опцию. Запустите прог-

рамму на счет, чтобы посмотреть, насколько правильно она ра-

ботает. Замечание: Для этой цели необходимо ввести правило

process(5) и дополнить модуль menu ссылкой на него. Требуется

также написать правила, похожие на правило dbrd и его вспомо-

гательные модули. Вместо выборки данных об одной из команд

они должны перебирать все имеющиеся в БД записи. Эту операцию

позволит проделать метод отката после неудачи.

9.9. Измените программу "Университетский футбол" так, чтобы

она выдавала лишь выборочные сведения о футбольных командах.

Улучшите формат выдачи, чтобы работа с БД стала бы еще более

удобной с вашей точки зрения.

9.5. Возможные улучшения системы управления базами данных

Вы познакомились с двумя примерами работающих СУБД: одна

из них является резидентной, другая располагает БД на внешнем

носителе, диске. Меню обоих систем содержат опции занесения

данных в базу, удаления их, а также выборки нужных данных.

Однако, может возникнуть необходимость и в других системных

опциях. Эти опции перечислены ниже, вы можете попытаться по-

экспериментировать с ними, когда будете достаточно свободно

ориентироваться в принципах построения СУБД.

- Verifying data entry (проверка введенных данных)

Бывает полезно проверить введенные с клавиатуры данные перед

тем, как заслать их в БД. Словом, Ваша программа должна вы-

вести данные на экран и дать пользователю возможность убе-

диться в их правильности. Если пользователь обнаружит во введ

енном тексте ошибки, он должен иметь возможность отменить

этот ввод и набрать данные заново.

- Еditing data (редактирование данных)

Ваша СУБД сильно выиграет, если будет предусмотрена возмож-

ность редактирования имеющихся в базе данных. Введение этой

операции означает добавления в программу модуля, который выс-

вечивает данные на экране, воспринимает сделанные пользовате-

лем изменения и производит перезапись данных в файл.

- Performing numerical computations (возможность численных

преобразований)

Представляемый системой управления БД сервис может включать и

такие возможности, как, например, возможность сложить новые

набранные какой-либо командой очки с уже имеющимся в базе по-

казателем.

- дополнительные предикаты БД

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

базы данных. Так в базу "Университетский футбол" можно доба-

вить предикат, работающий со сведениями о тренерах:

coach(name,team,personal_statistics)

- Hardcopy output (вывод на принтер ответа системы на запрос)

Полезно будет добавить в главное меню опцию, позволяющую по

желанию переадресовать выдачу системы с экрана на принтер и

наоборот.

- Natural language (возможность диалога с программой на ес-

тественном языке)

Значительный интерес представляют системы, использующие в ди-

алоге с пользователем не меню, а естественно-языковый интер-

фейс, понимающий человеческий язык в рамках некоего ограни-

ченного словаря терминов. Способы создания подобных систем

будут обсуждаться в гл. 11.

Предложенные улучшения позволят СУБД стать более гибкой,

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

улучшений может быть и продолжен; мы надеемся, что работа в

этом направлении даст вам возможность должным образом оценить

простоту и мощь предлагаемого языка; Турбо-Пролог обладает

всеми средствами, необходимыми для создания динамических баз

данных.

9.6. Заключение

В данной главе состоялось знакомство с основными поняти-

ями, касающимися баз данных. Вы увидели, что представляют со-

бой на деле реляционные БД, и как они соотносятся с БД Турбо

-Пролога. Было также показано, как проектировать и реализовы-

вать достаточно простые, однако применимые на практике дина-

мические базы данных Турбо-Пролога, как резидентные, так и

нерезидентные. Одновременно было продемонстрировано использо-

вание различных предикатов и правил для работы с файлами, об-

суждавшиеся в предыдущих главах.

При проектировании применялись диаграммы потоков данных

(ДПД) и структурные схемы (СС), два инструмента программиро-

вания, с которыми вы ознакомились несколько раньше. Теперь вы

увидели, как они могут быть использованы в практических це-

лях, если следовать методологии структурного программирова-

ния.

Работа над составлением программ систем управления база-

ми данных (СУБД) позволила детально ознакомиться с вопросами

организации данных в БД и извлечения из нее необходимимой

пользователю информации. Таким образом вы получили представ-

ление об основополагающих идеях представления знаний. Даль-

нейшее освещение этого аспекта технологии проектирования баз

данных будет иметь место в следующей главе, рассматривающей

проектирование и разработку эксперных систем.

Наконец, были представлены две программы БД: "Футбольная

база данных" и "Университетский футбол". Приведенные в главе

упражнения способствуют тому, чтобы читатель поработал с эти-

ми программами, возможно, модифицировал и усложнил их. Полу-

ченные в работе с программами навыки являются хорошей основой

для написания программ собственных баз данных.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]