Логічне програмування мовою Prolog
Особливості мови Пролог
Пролог - це описова мова програмування, що використовується для вирішення завдань, в яких діють об'єкти та відносини між цими об'єктами.
Орієнтація Прологу - "нетрадиційні" застосування обчислювальної техніки: розуміння природної мови, бази знань, експертні системи та інші завдання.
Його принципова відмінність від традиційних мов програмування полягає у підході до опису способу розв'язання задачі: програма на Пролозі описує не процедуру розв'язання задачі, а логічну модель предметної галузі – деякі факти щодо властивостей предметної галузі та відносин між цими властивостями, а також правила виведення нових властивостей та відносин із вже заданих.
Програма на пролозі складається із пропозицій, які можуть бути фактами, правилами чи питаннями.
Правила зіставлення термів у системі Пролог
Терм - елемент Пролог-програми - або константа, або змінна, або структура.
Найважливіша операція над термами – зіставлення. Зіставлення – процес перевірки сумісності термів.
Два терми можна порівняти, якщо:
- змінним в обох термах можна присвоїти як значень об'єкти таким чином, що після підстановки вони стануть ідентичними.
Загальні принципи пошуку відповідей на питання системою Пролог
Питання в системі Пролог є послідовністю 1 або декількох цілей.
Щоб відповісти на запитання, Пролог намагається досягти всіх цілей. Досягти мети – це означає продемонструвати, що ціль є істиною, за умови, що відносини у програмі є істинними. Тобто. продемонструвати, що мета логічно випливає з фактів та правил, заданих у програмі.
Якщо питання містить змінні, то система Прологмає знайти конкретні об'єкти, під час використання яких мети досягаються.
Об'єкти даних
Об'єкти даних у Пролозі можуть бути простими даними та структурами. Прості дані можуть бути константами та змінними. Константи можуть бути атомами, числами та рядками.
Пролог-система розпізнає тип об'єкта за його синтаксичною формою у тексті програми.
Атом - комбінація літер, цифр і символу підкреслення, що починається з малої літери. Приклади: a, "це_атом", "t his_is_atom".
Змінна - комбінація літер, цифр і знака підкреслення, що починається з великої літери. Приклади: V, Це_змінна25.
Структуровані об'єкти
Структурні об'єкти (чи навіть структури) - це об'єкти, які з кількох компонент. Ці компоненти, своєю чергою, може бути структурами.
Основною характеристикою структури є її розмірність (або арність) – число термів у списку.
Структури у програмі поводяться як єдині об'єкти. Щоб об'єднати компоненти в структуру, потрібно вибрати функтор (ім'я відносини, що утворюється між елементами структури) .
Структура програми
Програма на Турбо Пролозі складається з наступних семи розділів:
- директиви компілятора – додаткові інструкції з обробки програми;
- CONSTANTS- розділ опису констант;
- DOMAINS- розділ опису доменів;
- DATABASE- розділ опису предикатів внутрішньої бази даних;
- PREDICATES- розділ опису предикатів;
- CLAUSES- розділ опису пропозицій;
- GOAL- розділ опису внутрішньої мети.
Директива trace застосовується при налагодженні програми для трасування.
У програмі не обов'язково мають бути всі цірозділи. Так, наприклад, вона може складатися з одного опису мети:
Як правило, програма містить щонайменше розділи PREDICATES і CLAUSES.
Якщо програма запускається в середовищі розробки Турбо Прологу, розділ GOAL необов'язковий. При написанні програми, яка залежить від середовища розробки, у ній необхідно вказати внутрішню мету.
У програмі може бути декілька розділів описів DOMAINS, PREDICATES, DATABASE та CLAUSES. Однак розділів GOAL не може бути більше одного.
Порядок розділів може бути довільним, але константи, домени і предикати повинні бути визначені до їх використання. Однак у розділі DOMAINS можна посилатися на домени, які будуть оголошені пізніше.
Арифметичні вирази
Пролог не призначений для програмування завдань із великою кількістю арифметичних операцій. Для цього застосовуються процедурні мови програмування. Однак до будь-якої Пролог-системи включаються всі звичайні арифметичні оператори:
mod залишок від поділу цілих чисел,
div цілісний поділ.
Якщо Х - арифметичне вираз, то список [X] також є арифметичним виразом, наприклад [1,2,3]. Перший елемент списку використовується як операнд у виразі: X is ([l,2,3]+5) має значення 6.
Порівняння результатів арифметичних виразів
Системні предикати =:=, =\=, >, = і Y Х більше Y
Х = Y Х більше або дорівнює Y
Робота з файлами
Доступ до файлу може здійснюватися у двох режимах – бінарному та текстовому.
filemode(SymbolicFileName,Mode) - спеціальний предикат визначення виду доступу до файлу (параметр Mode приймає одне з двох значень:
Подальший виклад стосується тільки роботи з файлами в текстовійрежимі.
Щоб працювати з файлом на зовнішньому носії, його потрібно відкрити або створити. Відкрити файл можна для читання, запису, модифікації. Відкрити можна практично необмежену кількість файлів, стільки, скільки дозволяють установки операційної системи.
Предикат openread(SimbolicFileName,OSFileName) відкриває файл лише для читання. Якщо файл із зазначеним зовнішнім ім'ям не буде виявлено, предикат зазнає невдачі та виводить відповідне повідомлення про помилку.
Предикат openwrite(SimbolicFileName,OSFileName) відкриває файл для запису. Цей предикат створює новий файл на диску. Якщо файл із вказаним зовнішнім ім'ям вже існує, він буде стертий. Якщо з якоїсь причини файл не може бути створений, предикат зазнає невдачі та виводить відповідне повідомлення про помилку.
Предикат openappend(SimbolicFileName,OSFileName) відкриває файл лише для дозапису до кінця файлу. Якщо файл із вказаним ім'ям не буде виявлено, предикат виводить відповідне повідомлення про помилку.
Предикат openmodify(SimbolicFileName,OSFileName) відкриває файл для читання та запису одночасно. Якщо файл із вказаним ім'ям не буде виявлено, предикат виводить відповідне повідомлення про помилку.
Щоб перевірити, чи існує файл із зазначеним ім'ям у вказаному місці, використовується предикат existfile(OSFileName). Цей предикат має один аргумент. Предикат дійсний, якщо файл з ім'ям, вказаним як його єдиний параметр, існує, і хибний — інакше.
Ці предикати пов'язують символічне ім'я файлу з фізичним ім'ям файлу, що відкривається.
Оскільки символ "\", який зазвичай використовується для розділення імен каталогів, застосовується в Турбо Пролозі для запису кодів символів, потрібно використовувати замістьодного зворотного слеша два ("\"). Наприклад, щоб вказати шлях "C:PrologBIN", потрібно записати рядок C:PrologBIN.
Щоб коректно закрити відкритий файл, використовується предикат closefile. Як його єдиний параметр вказується символічне ім'я файлу. Предикат у будь-якому випадку успішний, навіть якщо відповідний файл не був відкритий. Із закритим файлом можна працювати лише повністю.
Предикат deletefile(OSFileName) видаляє файл, вказаний як його єдиний параметр. Якщо видалити файл з якоїсь причини не виходить, цей предикат видає повідомлення про помилку.
Предикат renamefile(OldOSFileName, NewOSFileName) змінює ім'я файлу, вказаного як перший параметр, на ім'я, вказане як його другого параметра. Якщо не існує файлу, ім'я якого вказано в першому параметрі, або існує файл, ім'я якого вказано в другому параметрі, предикат видасть повідомлення про помилку.
Предикат eof(SymbolicFileName) (скорочення від End Of File - "кінець файлу") успішний, якщо досягнуто кінець файлу, інакше він неуспішний. Як його єдиний вхідний параметр вказується символічне ім'я файлу. Він зазвичай використовується для організації рекурсивного зчитування всіх компонентів файла. Якщо його спробувати застосувати до файлу, відкритого для запису, буде видано повідомлення про помилку.
Предикат file_str(SymbolicFileName,String) повністю читає символи файлу в рядок або, навпаки, записує вміст рядка у файл, залежно від того, чи вільний другий параметр цього предикату. Першим вхідним параметром цього предикату є символічне ім'я файлу, а другим - рядок, в який зчитується вміст файлу або з якого записується інформація до нього.
Предикат flush(SimbolicFileName)використовується для примусового запису файл внутрішнього буфера, виділеного для файлу, вказаного в його єдиному параметрі. Зазвичай він використовується під час роботи з принтером.
Список задається перерахуванням елементів списку через кому у квадратних дужках.
Елементи списку можуть бути будь-якими, у тому числі складовими об'єктами. Зокрема, елементи списку можуть бути списками.
У розділі опису доменів списки описуються так:
Зірочка після імені домену вказує, що ми описуємо список, що складається з об'єктів відповідного типу.
[monday, tuesday, wednesday, thursday, friday, saturday, sunday] – список, елементами якого є англійські назви днів тижня;
["понеділок", "вівторок", "середовище", "четвер", "п'ятниця", "субота", "неділя"] - список, елементами якого є українські назви днів тижня;
[1, 2, 3, 4, 5, 6, 7] - список, елементами якого є номери днів тижня;
['п', 'в', 'с', 'ч', 'п', 'с', 'в'] — список, елементами якого є перші символи українських назв днів тижня;
[] - Порожній перелік, тобто. список, який містить елементів (у мові функціонального програмування Лисп він позначається nil).
Рекурсивне визначення списку
Список - це структура даних, яка визначається таким чином:
- порожній список ([]) є списком;
- структура виду [HT] є списком, якщо H - перший елемент списку (або кілька перших елементів списку, перерахованих через кому), а T - список, що складається з елементів вихідного списку, що залишилися.
Це визначення дозволяє організовувати рекурсивну обробку списків, розділяючи непустий список на голову і хвіст.
Робота зі списками
Предикат дозволяє обчислити довжину списку.
Предикат, що дозволяє перевіритиприналежність елемента списку(перший аргумент - потрібне значення, другий - список, в якому проводиться пошук).
Предикат, що дозволяєз'єднати два списки в один. Перші два аргументи предикату будуть представляти списки, а третій - результат з'єднання.
Цей предикат можна застосовувати для вирішення кількох завдань:
- для з'єднання списків:
- ?-conc([1, 2, 3], [4, 5], X) а X = [1, 2, 3, 4, 5]
- для того, щоб перевірити, чи вийде при об'єднанні двох списків третій:
- ?-conc([1, 2, 3], [4, 5], [1, 2, 5]) а No
- длярозбиття списку на підписки:
- Або поставити його безпосередньо:
Предикат, що дозволяєзаписати елементи списку у зворотному порядку(перший аргумент - вихідний список, другий - список, що отримується в результаті запису елементів першого аргументу у зворотному порядку).
Інший спосіб реверсу:
Предикат,дозволяє отримувати елемент списку за його номером(перший аргумент - вихідний список, другий аргумент - номер елемента і третій - елемент списку, вказаного як перший аргумент предикату, що має номер, вказаний як другий аргумент).
Предикат, що перевіряє, чи є елемент списком.
Предикат,перетворює список на однорівневий(перший аргумент - вихідний список, другий - результат).
Предикат,що видаляє всі входження заданого значення зі списку(перший параметр відповідає списку, другий - вихідному значенню, а третій - результату видалення з першого параметра всіх входжень другого параметра).
Якщо потрібновидалити не всі входженняпевного значення в список, а тільки перше, то :
Предикат,додає елемент до списку(перший параметр - елемент, що вставляється, другий - вихідний список, а третій - результат).
Але якщо виникає необхідністьдодавати тільки, якщо елемент відсутній, то можна використовувати правило:
Перевірка типів термів
Вбудовані предикати для перевірки типів термів:
atom(X) -істина, якщо X-атом.
integer(X) - істина, X-ціле.
float(X) – істина, якщо Х – дійсне число.
compound(X) – істина, якщо Х – складовий терм.
atomic(X) - істина, якщо X-ціле або атом.
var(X) - істина, якщо X-не конкретизована змінна.
nonvar(X) - істина, якщо X-терм, відмінний від змінної, або вже конкретизована змінна.
ground (Х) - істина, якщо Х не містить вільних змінних.
number(Х) – істина, якщо Х – число.
string(Х) – істина, якщо Х – рядок.
Операції з базами даних
Пролог-программу можна як реляційну базу даних, тобто. опис деякої множини відносин.
Опис відносин є або у явному вигляді (факти), або в неявному вигляді (правила).
assert(d) завжди успішний і додає факт d до бази даних;
retract(d) видаляє факт, який можна порівняти з d;
asserta(d) - забезпечує запис початку бази даних нового факту для заданого отношения;
assertz(d) - забезпечує запис у кінець бази даних нового факту для заданого відношення.
Оголошення динамічної бази даних здійснюється за допомогою ключового слова database.