те же предикаты assert/1 и retract/1, менять значение этой переменной, уничтожить её, когда необходимость в ней исчезнет.
Ниже (код 8.2) приводятся определения некоторых полезных предикатов для работы с такими глобальными переменными (естественно, можно придумать и еще какие-нибудь):
ini_bag/2 – создать переменную с данным именем и данным начальным значением,
ini_bag/1 – создать переменную с данным именем и пустым списком в качестве начального значения,
dob_bag/3 – добавить в список новый элемент, выдать старое значение списка,
sum_bag/3 – прибавить к числовому значению переменной данное число, выдать старое значение,
inc_bag/2 – прибавить единицу, выдать старое значение, dec_bag/2 – вычесть единицу, выдать старое значение, zam_bag/3 – заменить старое значение новым,
fin_bag/2 – уничтожить переменную с данным именем и выдать
ее значение.
Код 8.2
ini_bag(Bag, Value) :- assert(bag(Bag, Value)). ini_bag(Bag) :- assert(bag(Bag, [])).
dob_bag(Bag, New, Old) :- retract(bag(Bag, Old)), assert(bag(Bag, [New|Old])), !.
sum_bag(Bag, N, Old) :- retract(bag(Bag, Old)), New is Old + N, assert(bag(Bag, New)), !.
inc_bag(Bag, Old) :- retract(bag(Bag, Old)), inc(Old, New), assert(bag(Bag, New)), !.
111
dec_bag(Bag, Old) :- retract(bag(Bag, Old)), dec(Old, New), assert(bag(Bag, New)), !.
zam_bag(Bag, New, Old) :- retract(bag(Bag, Old)), assert(bag(Bag, New)), !.
fin_bag(Bag, Value) :- retract(bag(Bag, Value)).
Пример 8.2. В качестве примера применения глобальных переменных рассмотрим задачу обработки отношения, представленного набором фактов, с целью получения некоторых характеристик этого отношения, в частности:
максимального значения данного числового аргумента,
суммы значений данного числового аргумента,
списка значений данного нечислового аргумента.
Для определенности, рассмотрим конкретное отношение книга/10, содержащее библиотечные данные о книгах. Помимо самого отношения, база данных содержит факт, позволяющий судить о структуре этого отношения (в частности, об именах аргументов или атрибутов):
rel_str(книга(шифp(_), автоp(_), название(_),
томов(_), том(_), стpаниц(_), год(_), издательство(_), гоpод(_), аннотация(_))).
Анонимные переменные в этой структуре изображают «ячейки памяти», в которых могут храниться какие-нибудь сведения об аргументах, например их тип, шаблон или что-то еще.
Пусть отношение содержит следующие факты (код 8.3):
Код 8.3
книга(7008991, 'Пушкин А.С.', 'Евгений Онегин. Поэмы', 1, 1, 368, 1970, 'Художественная Литература', 'Москва', _).
книга(7805540, 'Пушкин А.С.', 'Стихотворения. Поэмы', 1, 1, 416, 1978, 'Русский язык', 'Москва', _).
112
книга(8606115, 'Булгаков М.А.', 'Мастеp и Маpгаpита', 1, 1, 416, 1986, 'Лиесма', 'Рига', _).
книга(8711803, 'Достоевский Ф.М.', 'Подpосток',
1, 1, 576, 1987, 'Московский pабочий', 'Москва', _).
книга(9009366, 'Достоевский Ф.М.', 'Бесы',
1, 1, 672, 1990, 'Художественная литеpатуpа', 'Москва', _).
книга(9110577, 'Достоевский Ф.М.', 'Бpатья Каpамазовы', 2, 1, 416, 1991, 'Пpавда', 'Москва', _).
книга(9110578, 'Достоевский Ф.М.', 'Бpатья Каpамазовы',
2, 2, 529, 1991, 'Пpавда', 'Москва', _).
Допустим, что нужно найти книгу с максимальным числом страниц, общее число страниц во всех имеющихся книгах, а также список авторов всех книг.
Эту задачу легко решить на Прологе с использованием представленных выше глобальных переменных. Для этого создадим три глобальные переменные с именами max, itog и avtor_list.
Начальные значения этих переменных (_, 0), 0, []. Их конечные значения:
пара, состоящая из шифра книги с максимальным числом страниц и этого числа;
общее число страниц всех книг;
список авторов всех книг.
Программа на Прологе для решения данной задачи такова:
Код 8.4
itogi(Res1, Res2, Res3):-
ini_bag(max, (_,0)), ini_bag(itog, 0), ini_bag(avtor_list),
cycle,
fin_bag(max, Res1), fin_bag(itog, Res2), fin_bag(avtor_list, List),
sort(List, Res3). cycle:-
'книга'(A1, A2, _, _, _, A6, _, _, _, _), max(A1, A6),
113
itog(A6), avtor_list(A2), fail.
cycle :- !.
max(Sh, Str):- bag(max, (_, Old)), Str > Old, !,
zam_bag(max, (Sh, Str), (_, Old)). max(_,_):-!.
itog(Str):- sum_bag(itog, Str, _).
avtor_list(Avt):- dob_bag(avtor_list, Avt, _).
Обратившись к Прологу с запросом
?- itogi(Res1, Res2, Res3).
для приведенного множества книг получим следующее решение
данной задачи:
Res1 = (9009366, 672) Res2 = 3393
Res3 = ['Булгаков М.А.', 'Достоевский Ф.М.', 'Пушкин А.С.'].
Отметим, что в данной программе используется возвратный способ организации цикла cycle – с помощью предиката fail. При этом предикаты max/2, itog/1, avtor_list/1 должны работать безвозвратно, а по возврату происходит обращение лишь к фактам книга/10 с просмотром всего этого отношения.
4. Создание утилит для работы с базой данных
В приведённом выше примере очевидна одна негативная особенность: при написании определения предиката cycle программист был вынужден обращаться к довольно громоздкой структуре отношения, выделяя нужные аргументы, заключенные в ее глубине. Было бы еще хуже, если бы запросы к библиотечной базе дан-
114
ных понадобилось составлять непрограммирующему пользователю.
Пример 8.3. Рассмотрим следующие запросы к библиотечной базе данных:
«Найти авторов книг, изданных в городе Рига»,
«Указать названия, авторов и издательства двухтомных изданий»,
«Какие книги Пушкина А.С., изданные до 1990 года, имеются в базе данных?»,
«Книги каких немосковских издательств имеются в базе дан-
ных?».
Пользователь вынужден указывать те места в структуре книга/10, в которых находятся интересующие его атрибуты.
Естественным желанием программиста – составителя определений на Прологе – является освободить пользователя от необходимости знать структуру отношения и предоставить ему полезные утилиты для работы с базой данных.
Следующая программа (код 8.5) демонстрирует возможность
работы с такого рода утилитами.
Код 8.5
book_menu:-
book_attrib(L), book_menu(L).
book_menu([]):-
write('Шифр - шифр книги (ключ отношения)'), !.
book_menu([A|T]):- write(A), nl, book_menu(T).
book_attrib(['автоp(Шифр, Автор)',
'название(Шифр, Название)', 'томов(Шифр, КоличТомов)', 'том(Шифр, Том)', 'стpаниц(Шифр, ЧисСтраниц)', 'год(Шифр, Год)',
'издательство(Шифр, Издательство)',
115