16
РОБОТА З ВНУТРІШНІМИ БАЗАМИ ФАКТІВ Лекція 6

Lect 6 prolog

Embed Size (px)

Citation preview

РОБОТА З ВНУТРІШНІМИ БАЗАМИ ФАКТІВ

Лекція 6

1. ВНУТРІШНЯ БАЗА ФАКТІВ Внутрішня база фактів складається з фактів, які ви можете

безпосередньо додавати і видаляти з вашої програми на Visual Prolog під час її виконання.

Ви можете оголошувати предикати, що описують внутрішню базу даних у розділі facts програми і застосовувати ці предикати таким же чином, як використовуються предикати, описані в розділі predicates.

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

Предикати consult /1 і consult /2 зчитують факти з файлу і додають їх до внутрішньої бази даних, a save /1 та save /2 зберігають вміст внутрішньої бази фактів у файлі.

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

1. ВНУТРІШНЯ БАЗА ФАКТІВ. ОГОЛОШЕННЯ

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

У цьому прикладі ви можете використовувати предикат person таким же чином, як предикат person таким же чином, як використовуються інші предикати (male, female, child). єдина відмінність полягає в тому, що ви можете додавати і видаляти факти для предиката person під час роботи програми.

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

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

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

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

1. ВНУТРІШНЯ БАЗА ФАКТІВ. ОГОЛОШЕННЯ

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

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

2. ВИКОРИСТАННЯ ВНУТРІШНЬОЇ БАЗИ ФАКТІВ. ДОСТУП

Предикати, що належать до внутрішньої бази фактів, доступні точно так само, як і інші предикати. Єдина видима відмінність полягає в тому, що оголошення таких предикатів розташоване в розділі facts замість розділу predicates. У наступному прикладі:

Ви можете викликати person з ціллю person (Name, 'F') для знаходження всіх жінок, або person ("Maggie", 'F') для перевірки того, що жінка на ім'я Maggie існує у вашій базі даних.

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

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

2. ВИКОРИСТАННЯ ВНУТРІШНЬОЇ БАЗИ ФАКТІВ. ОНОВЛЕННЯ

Під час виконання факти можуть бути додані до внутрішньої бази даних фактів за допомогою предикатів: assert, asserta і assertz, або шляхом завантаження фактів з файлу за допомогою consult.

Існує три предиката для додавання одного факту під час виконання:

Предикат asserta вставляє новий факт до бази даних фактів перед наявними фактами для даного предиката, a assertz вставляє факти після наявних фактів даного предиката.

Використання предиката assert дає результат, аналогічний використанню assertz.

Оскільки імена предикатів бази фактів унікальні всередині програми (для розділів глобальних фактів) або модуля (для розділів локальних фактів), для предикатів asserta і assertz завжди відомо, в яку базу даних фактів потрібно додавати факт. Однак для того, щоб забезпечити роботу з необхідною базою даних фактів, в цілях перевірки типу можна використовувати необов'язковий другий аргумент.

2. ВИКОРИСТАННЯ ВНУТРІШНЬОЇ БАЗИ ФАКТІВ. ОНОВЛЕННЯ

Перший предикат прикладу вставить факт про Suzanne, описаний предикатом person, після всіх фактів person, що зберігаються на поточний момент в пам'яті.

Другий - факт про Michael перед усіма наявними фактами предиката person.

Третій - факт про John після всіх інших фактів likes в базі даних фактів likesDatabase.

А четвертий вставить факт про Shannon в тій же базі даних фактів перед усіма іншими А четвертий вставить факт про Shannon в тій же базі даних фактів перед усіма іншими фактами likes.

Після виклику цих предикатів база фактів буде виглядати так, як ніби ви почали роботу з наступними фактами:

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

2. ВИКОРИСТАННЯ ВНУТРІШНЬОЇ БАЗИ ФАКТІВ. ЗЧИТУВАННЯ

Предикат consult зчитує з файлу fileName факти, описані в розділі facts, і вставляє їх у програму в кінець відповідної бази фактів. Предикат consult має один або два аргументи:

consult (fileName)% (i)

consult (fileName, databaseName)% (i, i)

Однак на відміну від assertz, якщо викликати consult тільки з одним аргументом (без імені бази фактів), то будуть зчитані лише факти, які були описані у розділі без імені (за замовчуванням dbasedom).

Якщо викликати consult з двома аргументами (ім'я файлу і ім'я бази фактів), то будуть перевірені тільки факти з вказаної бази фактів. Якщо файл містить ще що-небудь, окрім фактів зазначеної бази, то предикат consult, коли він дійде до цього рядка, поверне фактів зазначеної бази, то предикат consult, коли він дійде до цього рядка, поверне помилку.

Предикат consult зчитує по одному факту. Якщо файл містить десять фактів, а у сьомому факті є яка-небудь синтаксична помилка, consult занесе шість перших фактів в базу даних фактів, після чого видасть повідомлення про помилку.

Предикат consult може зчитувати файли тільки в тому форматі, який створює save. Файли не повинні містити:

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

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

коментарів;

порожніх рядків;

ідентифікаторів (symbol) без подвійних лапок.

2. ВИКОРИСТАННЯ ВНУТРІШНЬОЇ БАЗИ ФАКТІВ. ПРОГРАМНЕ

ЗНИЩЕННЯ ФАКТІВ

Предикат retract уніфікує факти і знищує їх з внутрішньої бази фактів. Він має наступний формат:

retract (<the fact>)% (i)

retract (<the fact>, databaseName)% (i, i)

Предикат retract видаляє перший факт з бази даних, який збігається з фактом <the fact>, пов'язуючи вільні змінні <the fact> під час виконання програми. Знищення фактів з внутрішньої бази фактів еквівалентно програми. Знищення фактів з внутрішньої бази фактів еквівалентно процесу доступу до них з побічним ефектом знищення уніфікованих фактів.

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

2. ВИКОРИСТАННЯ ВНУТРІШНЬОЇ БАЗИ ФАКТІВ. ПРОГРАМНЕ

ЗНИЩЕННЯ ФАКТІВ

Припустимо, у програмі є наступні розділи facts:

Маючи такі розділи facts, Visual Prolog можна задати наступні цілі:

Мета (%1) знищить перший факт person про Fred з бази фактів dbasedom.

З допомогою мети (%2) з бази фактів likesDatabase буде знищений перший факт, що співпадає з likes (X, "broccoli"). У разі обох цілей, Visual Prolog знає, з якої бази проводити знищення, оскільки імена предикатів бази фактів унікальні:

предикат person знаходиться тільки в неіменованій базі даних фактів, a likes -тільки в базі likesDatabase.

мета (%3) і (%4) показують, як можна використовувати для перевірки типу другий аргумент.

мета (%3) успішно реалізується, знищуючи перший факт, що співпадає з likes (_, "money") з likesDatabase, а мета (%4) видасть помилку, тому що немає (і не може бути) факту person в базі даних фактів likesDatabase.

Повідомлення про помилку виглядає наступним чином:

2. ВИКОРИСТАННЯ ВНУТРІШНЬОЇ БАЗИ ФАКТІВ. ПРОГРАМНЕ

ЗНИЩЕННЯ ФАКТІВ

Предикат retractall знищує з бази фактів всі факти, що збігаються зі зразком <the fact>. Предикат retractall має наступний формат:

retractall (<the fact>)

retractall (<the fact>, databaseName)

Дія retractall аналогічна дії, заданій

retractall (X): - retract (X), fail,

retractall (_).

але значно швидша.але значно швидша.

Очевидно, предикат retractall завжди завершується успішно. З retractall вихідні значення отримати не можна. Це означає, що, як і у випадку not, потрібно використовувати символ підкреслення для вільних змінних.

Так само, як і у випадку предикатів assert і retract, для перевірки типу можна використовувати другий аргумент. І, як у випадку предиката retract, якщо при виклику retractall використовується символ підкреслення, то із зазначеного розділу facts можна знищити всі факти.

Наступна ціль знищує всі факти про чоловіків з бази фактів з фактами person:

retractall (person (_, _, _, male)).

Наступна ціль знищує всі факти з бази mydatabase.

retractall (_, mydatabase).

2. ВИКОРИСТАННЯ ВНУТРІШНЬОЇ БАЗИ ФАКТІВ. ПРОГРАМНЕ

ЗБЕРЕЖЕННЯ ФАКТІВ

Предикат save зберігає факти з вказаної бази фактів (розділу facts) у файлі.

Цей предикат має один або два аргументи:

save (fileName)% (i)

save (fileName, databaseName)% (i, i)

При виклику предиката save тільки з одним аргументом (без імені бази При виклику предиката save тільки з одним аргументом (без імені бази фактів), у файлі fileName будуть збережені факти з бази фактів dbasedom, що використовується за замовчуванням.

При виклику предиката save з двома аргументами (ім'я файлу і ім'я бази фактів), у вказаному файлі будуть збережені факти з розділу facts бази фактів з ім'ям databaseName.

2. ВИКОРИСТАННЯ ВНУТРІШНЬОЇ БАЗИ ФАКТІВ. КЛЮЧОВІ

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

facts [- <databasename>]

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

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

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

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

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

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

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

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

2. ВИКОРИСТАННЯ ВНУТРІШНЬОЇ БАЗИ ФАКТІВ. КЛЮЧОВІ

СЛОВАФакти, оголошені з ключовим словом nondeterm

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

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

Факти, оголошені з ключовим словом determ

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

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

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

замість

2. ВИКОРИСТАННЯ ВНУТРІШНЬОЇ БАЗИ ФАКТІВ. КЛЮЧОВІ

СЛОВА

Факти, оголошені з ключовим словом single

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

facts - properties

single numberWindows_s (integer)

clauses

numberWindows_s(0).

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

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

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

numberWindows_s (Num),

ніколи не завершується неуспіхом, якщо Num - вільна змінна.

Отже, зручно використовувати одноразові факти у предикаті, оголошених з типом детермінізму procedure.

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

3. ПРИКЛАДИ

ВИКОРИСТАННЯ

ВНУТРІШНЬОЇ БАЗИ

ФАКТІВ