Особливості представлення динамічних баз даних у Visual Prolog

 

Для опису внутрішньої бази даних у Visual Prolog використовується ключове слово facts, яке визначає початок оголошення розділу facts. Розділ facts складається з послідовності оголошень предикатів, що описують відповідну внутрішню базу фактів. Під час виконання можна за допомогою предикатів стандартних asserta і assertz додавати факти (але не правила) в базу фактів. Або, викликавши стандартний предикат consult, ви можете витягнути факти, що додаються, з файлу на диску.

Слід зазначити такі два обмеження на предикати, оголошені в розділі фактів:

– дозволяється додавати в базу даних тільки факти, але не правила;

– факти бази не можуть містити вільні змінні.

Допускається наявність декількох розділів facts, але для цього потрібно явно вказати ім'я кожного розділу facts.

facts — mydatabase

myFirstRelation(integer) mySecondRelation(real, string) myThirdRelation(string)

Опис розділу facts з ім'ям mydatabase створює базу даних фактів з ім'ям mydatabase. Якщо не задати ім’я динамічної базі фактів, то за замовчуванням їй привласнюється стандартне ім'я dbasedom. Програма може містити локальні безіменні розділи фактів, тільки якщо вона складається з одного модуля, який не оголошений як частина проекту. Візуальне середовище розробки (VDE) компілює програмний файл як єдиний модуль тільки при використанні утиліти Test Goal. Інакше, безіменний розділ фактів повинен бути оголошений глобальним. Для цього потрібно перед ключовим словом facts поставити ключове слово global.

Імена предикатів бази фактів повинні бути унікальними в модулі (початковому файлі); у двох різних розділах facts не можна застосовувати однакові імена предикатів. Аналогічно, не можна використовувати однакові імена предикатів в розділах facts і predicates. Проте імена предикатів, визначених в локальних facts-розділах, є локальними для модуля, де вони оголошені, і не конфліктують з локальними іменами предикатів/фактів, оголошених в інших модулях.

За своєю природою предикати в розділі facts завжди недетерміновані. Оскільки факти можуть бути додані у будь-який момент під час виконання програми, компілятор завжди повинен враховувати, що існує можливість знайти альтернативне рішення в ході пошуку з поверненням. Якщо в розділі facts є предикат, для якого ніколи не буде більше одного факту, то можна декларувати це, написавши перед оголошенням предиката факту ключове слово determ (або ключове слово single, якщо предикат завжди повинен мати один і лише один факт):

facts

determ daylight_saving(integer)

Відповідно, при спробі додати новий факт для детермінованого предиката бази фактів, який вже має факт, завжди виникатиме помилка.

У оголошенні розділу facts можна використовувати такі необов'язкові ключові слова:

facts [– <databasename>]

[nocopy][{ nondeterm | determ | single }]

dbPredicate ['(' [Domain [ArgumentName]]* ')']

Необов'язкові ключові слова nondeterm, determ і single оголошують режим детермінізму оголошеного предиката бази фактів dbPredicate. Тільки одне з них можна використовувати. Якщо режим детермінізму предиката бази фактів не заданий явно, тоді за умовчанням приймається значення nondeterm. Режим nondeterm для предикатів баз фактів завжди задається за умовчанням, не залежно від установки прапорця Default Predicate Mode в діалоговому вікні Compiler Options VDE.

nondeterm – визначає, що база фактів може містити будь-яке число фактів для предиката бази фактів dbPredicate. Це режим за умовчанням;

determ – визначає, що база фактів може містити не більше одного факту для предиката бази фактів dbPredicate;

single – визначає, що база фактів завжди містить один і лише один факт для предиката бази фактів dbPredicate.

посору – звичайно, коли предикат бази фактів викликаний для зв’язування змінної з рядковим або складеним об'єктом, викликані дані копіюються з купи (heap) в глобальний стек Visual Prolog (GStack). посору оголошує, що дані не будуть скопійовані, а змінні посилатимуться безпосередньо на дані факту, що зберігаються в купі. Це може значно збільшити ефективність, але якщо копія не була зроблена, після видалення факту змінна указуватиме на якесь „сміття”. Тому використовувати такий підхід слід обережно.

global – визначає, що база фактів – глобальна. Надійна техніка програмування вимагає, якомога меншого використання глобальних фактів. Натомість можна застосовувати глобальні предикати, що працюють з локальними фактами.

Ключове слово nondeterm визначає режим за замовчуванням для фактів (предикатів бази фактів), оголошених в розділі facts. Якщо жодне із слів determ або single не використане при оголошенні фактів, компілятор застосовує режим nondeterm. Звичайно за своєю природою предикати бази фактів недетерміновані. Оскільки факти можуть бути додані у будь-який момент виконання програми, компілятор повинен враховувати, що під час пошуку з поверненням можливо знаходження альтернативних рішень.

Ключове слово determ визначає, що база фактів може містити не більше одного факту для предиката бази фактів, оголошеного з цим ключовим словом. По цьому, якщо програма намагається встановити інший такий факт у базі даних фактів, Пролог згенерує помилку. Отже, програмісту слід з особливою обережністю використовувати детерміновані факти.

Оголошення факту детермінованим дозволяє компілятору генерувати ефективніший код, і при виклику таких предикатів не буде генеруватися повідомлення про можливий недетермінований виклик. Це корисно для прапорців, лічильників і інших подібних об’єктів.

Особливу увагу слід звернути на те, що при видаленні факту, який оголошений determ, виклик недетермінованих предикатів retract/1 і retract/2 (де 1, 2 означає кількість аргументів в предикаті) буде детермінованим. Тому, якщо відомо, що у будь-який момент часу база фактів містить не більше одного факту counter, можна написати:

facts

determ counter(integer CounterValue)

goal

retract(counter(CurrentCount)), % Пролог не встановить точку відкату Count= CurrentCount + 1, assert(counter(Count))

замість

facts

counter(integer CounterValue)

predicates

determ retract_d(dbasedom)

clauses

retract_d(X): — retract(X)!. % детермінований предикат

goal

retract_d(counter(CurrentCount)), % Пролог не встановить точку відкату Count= CurrentCount + 1, asserta(counter(Count))

Ключове слово single визначає, що база фактів завжди містить один і лише один факт для предиката бази фактів, оголошеного з ключовим словом single. Тому single (одноразові) факти повинні бути вже відомі, коли програма викликає мету; отже, вони повинні ініціалізуватися в розділах clauses в початковому коді програми. Наприклад:

facts – properties

single numberWindows_s(integer)

clauses

nuraberWindows_s(0).

Одноразові факти не можуть бути видалені. Якщо спробувати видалити одноразовий факт, компілятор згенерує помилку. У більшості випадків компілятор може визначити спробу видалення одноразового факту на етапі компіляції. Оскільки один екземпляр одноразового факту завжди існує, виклик одноразового факту ніколи не завершується неуспіхом, якщо він викликаний з вільними аргументами.

Наприклад, наступний виклик:

numberWindows_s(Num)

ніколи не завершується неуспіхом, якщо Num – вільна змінна. Таким чином, зручно використовувати одноразові факти в предикатах, оголошених з типом детермінізму procedure.

Предикати assert, asserta, assertz і consult, застосовані до факту single, діють аналогічно парі предикатів retract і assert. А саме предикати assert (consult) змінюють існуючий екземпляр факту на вказаний новий.

Використання ключового слова single перед декларацією факту дозволяє компілятору отримати оптимізований код для доступу до одноразового факту і його модифікації. Наприклад, для предикатів assert, застосованих до одноразового факту, компілятор генерує код, який працює ефективніше, ніж пара предикатів retract і assert, застосованих до детермінованого факту (і тим більше, чим пара предикатів retract і assert, при використанні із звичайним (не детермінованим) фактом).