В рассматриваемую нами программу должны время от времени вноситься изменения. Укажем, в каких случаях это необходимо.
В базу данных требуется добавить информацию о новом человеке или удалить всю информацию о той или иной личности. Эти операции достаточно просто выполнить d помощью отношений add и delete.
В базу данных может потребоваться ввести дополнительную информацию о личности; причем ее следует поместить либо в один существующий подсписок, либо в несколько существующих подсписков, либо потребуется создать новый подсписок и включить данные в него. Такую возможность необходимо принять во внимание при конструировании правил, предназначенных для доступа к уже имеющейся в базе данных информации. Все изменения должны быть сведены только к включению в программу дополнительной информации и новых правил для доступа к ней.
Довольно часто требуется изменять данные, хранящиеся в базе. Характерным примером таких данных является текущая дата.
Отметим, что устройство, отсчитывающее время, или таймер, обычно полностью автономно и не прекращает своей работы даже тогда, когда отключается питание ЭВМ. Чтобы определить дату, достаточно обратиться к этому устройству. Именно это ср"азу после включения ЭВМ делает системная программа инициализации. Кроме того, существуют следующие способы определения даты: с помощью специальной программы, которая вызывается в тех случаях, когда для обработки запроса требуется дата; с помощью отношения, которое либо запрашивает у пользователя дату, либо побуждает ЭВМ модифицировать дату в соответствии с некоторым фиксированным правилом. Поскольку последним способом наиболее часто пользуются владельцы микроЭВМ, мы рассмотрим несколько возможных путей его реализации.
Читателям уже известен используемый в Пролог-системе способ модификации информации, основанный на отношении is-told. Для того чтобы воспользоваться им, необходимо загрузить в оперативную память модуль TOLD.
Напомним, что иногда текст программы занимает слишком много места и в связи с этим работа программы замедляется. Чтобы этого не было, следует после отладки программы удалить модули системы SIMPLE из памяти и все запросы формулировать, следуя требованиям стандартного синтаксиса. Однако удобно постоянно иметь в распоряжении систему SIMPLE. Поэтому, для того чтобы все же ускорить работу, мы введем в рассмотрение новую программу, которая связана главным образом с использованием даты для получения ответов на запросы.
Читателю, который совмещает чтение этой книги с работой на ЭВМ, к сожалению, придется удалить прежнюю программу и набрать новую, текст которой приведен ниже:
Betty bora (3 5 1950)
Joe bora (9 10 1917)
Helen bora (30 31950)
Tom bora (311 1960)
Bill bora (25 1 1960)
Ted bora (9 3 1954)
Mary born (1 1 1930)
Isabel born (31 12 1942)
X age Y if
X bora (Z x y) and
date now (z X1 Y1) and
(either x LESS X1 and / or x leq X1 and Z leq z) and
SUM(YyY1)
X age Y if
X bora (Z x y) and
date now (z X1 Y1) and
(either X1 LESS x and / or X1 leq x and z LESS Z) and
SUM(Z1yY1)and
SUM (Y1 Z1)
X leq X
X leq Y if
X ESSY date now (20 9 1985)
В ответ на запрос
all (х у z: x born у and x age z)
должны быть получены следующие ответы:
Betty (3 5 195 ∅) 35
Joe (9 1∅ 1917) 67
Helen (3 ∅ 8 1956) 29
Tom (3 11 195 ∅) 34
Bill (25 1 1943) 42
Ted (93 1954) 31
Mary (1 1 198 ∅) 5
Isabel (31 12 1942) 42
Теперь сформулируем правило, позволяющее модифицировать Дату:
update X if
now KILL and
(new date (X)) is-told and
(date now ?) add and
Продемонстрируем на примере, как оно работает:
is (update x)
[верно (модифицировать х)]
new date (X) ? ans (19 9 1985)
[новая дата (X) ? ответ (19 9 1985)]
Yes
[Да]
Когда текст программы будет выведен на печать, окажется, что старая дата уничтожена, а новая добавлена. Следует вводить только одну новую дату, поскольку все равно отношение "/" предотвратит использование всех дат, кроме одной. Если эта предосторожность не будет выполнена, новые даты будут запрашиваться до тех пор, пока от пользователя не будет получен ответ NO. Заметим, что при вводе необходимо дату заключать в круглые скобки.
Не прибегая к модификации отношения age, сформируем новое отношение, которое позволит одновременно изменить дату и определить возраст. Когда дату корректировать не надо, можно использовать описанные выше отношения:
X new-age Y if
update Z and
X age Y
Теперь программа будет работать следующим образом:
all (x у: х new-age у)
[определить все (х у: х имеет-новый-возраст у)]
new date (X) ? ans (12 12 1985)
[новая дата (X) ? ответ (12 12 1985)]
Betty 35
[Бетти 35]
Joe 68
[Джо 68]
и т. д.
Упражнение 3.9
Составьте запросы, позволяющие определить:
а. Кто моложе, чем Тед, и каков его возраст?
б. Кому 1 января 1975 г. было больше 18 лет?
в. Кому 31 декабря 2000 г. будет меньше 50 лет?
г. Кто в данный момент имеет один и тот же возраст?
д. У кого даты рождения совпадают?
е. Кто родился позднее 1 января 1950 г.?
Упражнение 3.10.
В табл. 3.2 приведены запасы стройматериалов, которыми располагает три строительных подрядчика.
Таблица 3.2
Напишите программу, которая позволит пользователю определить, какое количество указанного материала находится у данного поставщика, и, кроме того, даст возможность переопределить ресурсы поставщиков после покупки и продажи материалов.
Программисту, привыкшему работать на Бейсике, программа на Прологе для упражнения 3.10 покажется громоздкой и какой-то нескладной. На Бейсике все выглядело бы значительно проще: достаточно было бы нескольких операторов типа LET или одного FOR. Но в Прологе таких возможностей нет. Существует принципиальная разница в методах обработки данных, используемых Бейсиком и Прологом. В Бейсике переменные принимают глобальные значения, которые в процессе выполнения программы меняются в соответствии с выполняемыми операциями; в Прологе переменные не принимают глобальных значений и с ними связываются значения только в результате обработки запроса. Кроме того, в Прологе после обработки запроса последнее назначенное переменной значение не запоминается.
В языках, подобных Бейсику, данные являются динамическими или изменяемыми; в то же время данные в Прологе статичны или неизменны. Одна из ловушек, подстерегающих в Прологе тех, кто привык к Бейсику, заключается в том, что значения, вводимые с помощью отношения is-told, не сохраняются. Для того чтобы сохранить значения, необходимо использовать отношение add; для удаления старых значений можно применять отношение delete. Эти два отношения можно использовать для того, чтобы определить, сколько раз применялось заданное правило в процессе обработки запроса. Отметим, что эту же задачу на Бейсике решить несколько проще, чем на Прологе.
Предположим, требуется узнать, сколько раз программа ие-пользует дату в процессе обработки запроса о возрасте. Для этого необходимо создать два отношения: одно - для хранения тРебуемого числа и второе - для его модификации. Кроме того, Для того чтобы предусмотреть модификацию информации, необходимо добавить условие к правилу, использование которого контролируется.
В результате изменения, вносимые в программу, будут иметь вид:
date now (22 9 198S) if
A upcount
X upcount if
(X count Y) delete and
SUM(Y1Z) and
(X count Z) add and
/
A count ∅
В count ∅
С count ∅
D count ∅
Выполнение условия
if A upcount
приводит к замене предложения
A count N
предложением
A count N + 1
всякий раз, когда используется отношение date.
Остальные утверждения, включающие объекты В, С и D, потребуются, если понадобится контролировать какие-то другие отношения.
На запрос
all (x A count у : х age z and A count у)
теперь будут получены следующие ответы:
Betty A count 1
Helen A count 3
Bill A count 5
Ted A count 6
Mary A count 7
Joy A count 1∅
Tom A count 12
Подчеркнем, что отношение count позволяет определить общее число обращений к дате. Для Бетти, Теда и Мэри число таких обращений равно 1, для Элен, Билла и Тома - 2, для Джо - 3 и для Изабеллы - 4. Можно предположить, что программа, включающая отношения count и update, будет работать медленно.
Это действительно так, поскольку выполнение операций, связанных с отношениями add и delete, потребует значительного времени. Другими словами, описанный метод стоит использовать только для выполнения диагностических функций. Более того, в Пролог-системе есть специальный модуль TRACE, позволяющий следить за каждым шагом работы программы в процессе оценки запроса. Для того чтобы осуществить это, необходимо разместить модуль TRACE непосредственно перед программой пользователя. Но следует учесть, что он занимает достаточно много памяти- и поэтому его целесообразно использовать как средство обучения только вместе с небольшими программами. Если с помощью отношения count необходимо следить за работой нескольких правил, то было бы удобно иметь универсальное средство установки в ноль значений всех счетчиков, использование которого даст возможность избежать модификации каждого предложения. Ниже приведена программа, которая позволяет это сделать. В ней предусмотрено удаление всех имеющихся предложений отношения count и добавление новых для счетчиков А, В и С
zero if
(X count Y) delete and
(X count 0) add and
/
X reset if
Y isall (Y: Y count Z) and
X ON Y and
not X count 0 and
X zero
A count 5
В count 55
С count 23
Для установки в ноль всех счетчиков достаточно использовать следующий запрос
all (x: х reset)
В ответ будет напечатано С, В и А - именно в таком порядке. Если Вы теперь распечатаете текст программы, то увидите, что все счетчики установлены в ноль. Заметим, что отношение zero позволяет удалить из базы данных только одно утверждение вида
X count Y
Нам же необходимо удалить все. Для этого предлагается использовать стандартное отношение isall. Это отношение в данном примере дает возможность сформировать список Y, состоящий из всех первых аргументов отношения count. Причем порядок следования этих аргументов изменится на противоположный, т. е. Y = (С В А). Для ускорения работы программы выполнение отношения reset инициируется только тогда, когда данный счетчик не установлен в ноль, т. е. когда второй аргумент утверждения count не равен нулю.
Упражнение 3.11
а. Удалите условие
if A upcount
из отношения date и добавьте его к первому правилу отношения age. Кроме того, добавьте второй счетчик В ко второму правилу отношения age.
б. Составьте запрос, который даст возможность определить, сколько раз каждое правило, образующее отношение age, используется для определения возраста всех тех людей, информация о которых имеется в базе данных.
в. Попробуйте объяснить, почему данные о возрасте людей не выводятся в том же порядке, в котором расположены имена этих людей в базе данных.