Операции с базой данных
Ваза данных, в соответствии с реляционной моделью баз данных, представляет собой спецификацию набора отношений. Любая программа Prolog может рассматриваться как подобная база данных; в ней спецификация отношений частично является явной (факты), а частично неявной (правила). Некоторые встроенные предикаты позволяют модифицировать эту базу данных во время выполнения программы. Такое обновление осуществляется путем добавления новых предложений в программу или удаления существующих предложений (причем эти операции осуществляются во время выполнения программы). Для этого предназначены предикаты assert, asserts, assertz и retract. Цель asserttС)
всегда достигается и в качестве побочного эффекта вызывает подтверждение (assertion) предложения С, т.е. внесение его в базу данных. Цель
retract< С)
выполняет противоположное действие: удаляет предложение, которое согласуется с предложением С. Выполнение этих операций можно продемонстрировать на примере следующего диалога с системой Prolog:
?- crisis.
no
?- assert С crisis) .
yes
?- crisis,
yes
?- retractf crisis).
?- crises,
Таким образом, внесенные в базу данных предложения действуют точно так же, как часть "первоначальной" программы. Приведенный ниже пример показывает один из способов использования предикатов assert и retract для учета изменений ситуации. Предположим, что имеется следующая программа, в которой регистрируется состояние погоды:
Глава 7. Дополнительные встроенные предикаты
nice :-
sunshine, not raining.
funny :-
sunshine, raining.
disgusting :-
raining, fog.
raining. fog.
Ниже приведендиалог с этой программой, который показывает, как постепенно , изменяются содержимое базы данных и реакция программы.
?- nice.
по
?- disgusting.
yes
?- retract [ fog) .
yes
?- disgusting.
no
?- assert! sunshine).
yes
?- funny.
У- retract ( raining).
yes
?- nice.
yes
Вносить или извлекать из базы данных можно предложения любой формы. Но в зависимости от реализации Prolog может потребоваться, чтобы предикаты, добавляемые и извлекаемые с помощью предикатов assert/retract, были объявлены как динамические. ДЛЯ ЭТОГО используется директива dynamic( Predicatelndicator). Предикаты, внесенные в базу данных с помощью предиката assert, а не consult, автоматически рассматриваются как динамические.
Следующий пример показывает, что предикат retract также является недетерминированным: с помощью единственной цели retract может быть удален целый набор предложений путем перебора с возвратами. Предположим, что в программе, применяемой для "консультации", имеется следующий набор фактов:
fast ( aims .
slow! torn).
■pat) .
К этой программе можно добавить некоторое правило следующим образом:
?- assert! (faster[X,¥> :-
fastcxb slow(Y) ) ) .
yes
?- faster! a, B) .
A - ann
E = torn
?- retract ( sio>;(x) ) .
X = torn;
X - pat;
no
?- faster! ann, _).
no
Обратите вниманиена то, что при внесении в базу данных это правило (как параметр предиката assert) в соответствии с синтаксисом было заключено в круглые скобки.
162 Часть I. Язык Prolog
При внесении предложения в базу данных может потребоваться указать позицию, в которой это новое предложение должно быть вставлено в базу данных. Предикаты asserta и assertz предоставляют возможность управлять позицией вставки. Цель asserta(С) добавляет предложение С в начале базы данных, а цель
assertz(С)
вставляет предложение С в конце базы данных. Предполагается, что предикат assert эквивалентен assertz, как обычно предусмотрено в реализациях Prolog. В следующем примере демонстрируется, какое влияние на базу данных оказывают эти предикаты:
?- assert p(b>), aseertzl р(О), assert: p(d)), asserta ( p [an .
yes
?- P{X) X - a; X = b ; X = c,-
X = d
Предикаты consult и assertz связаны между собой определенной зависимостью. Получение консультации из файла с помощью предиката consult можно определить в терминах предиката asser z следующим образом: для получения консультации из файла прочитать каждый терм (предложение) файла и внести его в конец базы данных.
Одна из типичных областей применения предиката asserta состоит в сохранении уже вычисленных ответов на вопросы. Например, предположим, что в программе определен следующий предикат: solve.' Problem, solution)
Теперь системе можно задать некоторый вопрос и потребовать, чтобы она запом
нила ответ, для того, чтобы он мог использоваться в будущих вопросах:
?- solve) prob[ Solution),
eiS SCI l a solve f problem!. Solution)).
Если первая из приведенных целей достигается, то ответ (Solution) запоминается и используется наряду с любыми другими предложениями при формировании ответов на дальнейшие вопросы. Преимуществом такого "запоминания" ответом является то, что на дальнейшие вопросы, соответствующие подтвержденным фактам, система обычно находит ответ намного быстрее, чем на первый вопрос. После этого результат может быть просто выбран из базы данных как факт, не требуя вычисления в процессе, который, возможно, занимает много времени. Такой метод сохранения ранее полученных решений называют также кэшированием.
В одном из вариантов реализации этой идеи операция внесения в базу данных используется для выработки всех решений в форме таблицы фактов. Например, имеется возможность сформировать таблицу произведений всех пар целых чисел от О до 9 следующим образом: сформировать пару целых чисел X и V, вычислить выражение Z is л внести в базу данных три числа в виде одной строки таблицы произведений, а затем вызвать ситуацию недостижения цели. Эта ситуация приведет к тому, что в результате перебора с возвратами будет сформирована еще одна пара целых чисел и в таблицу будет введена еще одна строка и т.д. Эта идея реализована в приведенной ниже процедуре maketable.
maketable :-
L = [0,1,2, 3,4, 5, 6,7, В, 9],
member( X, L) , * Выооать первый коэффициент
member( Y, L) , ■ Выбрать второй коэффициент Z isX'Y, assert! product(X,Y,Z) >,
fail .
Глава 7. Дополнительные встроенные предикаты 163
Безусловно, что вопрос ?- maketable.
окончится неудачей, но в качестве побочного эффекта позволит ввести в базу данных всю таблицу умножения. После этого системе можно задать вопрос, например, какая пара чисел дает произведение 8:
?- product! к, В, 8). А = 1 В =8; А =2 В =4;
На данном этапе необходимо сделать одно замечание в отношении такого стиля программирования. Приведенные выше примеры показывали некоторые, безусловно, удобные способы применения предикатов assert и retract. Но при использовании этих предикатов необходимо соблюдать особую осторожность. Излишнее и непродуманное применение этих средств нельзя рекомендовать в качестве хорошего стиля программирования. Использование операций подтверждения и извлечения фактов и правил по сути приводит к модификации программы. Поэтому отношения, которые в какой-то момент были действительными, в другое время могут оказаться недействительными. В разное время на одни и те же вопросы система будет давать разные ответы. Поэтому применение значительного количества операций подтверждения и извлечения может затемнить смысл программы. В конечном итоге может оказаться, что поведение программы трудно понять, нелегко объяснить, и поэтому ей нельзя доверять.
Упражнения
7.6. Выполните указанные ниже действия после проведения упражнений с табли
цей product.
а) Составьте вопрос к системе Prolog для удаления всей таблицы product из базы данных.
6} Измените вопрос таким образом, чтобы он удалял только те записи, в которых произведение равно нулю.
7.7. Определите отношение
copy_tem{ Tern, Copy)
создающее такую копию Сору терма Terra, в которой переименованы все переменные. Программу решения" данной задачи легко сформировать с использованием предикатов asserta и retract. В некоторых реализациях Prolog уже предусмотрен такой встроенный предикат, copy_term.