- •Міністерство освіти і науки України Дніпропетровський національний університет
- •Програмування мовою пролог
- •Дніпропетровськ
- •1. Основи мови програмування пролог
- •1.1. Основні поняття
- •1.2. Синтаксис мови пролог
- •1.3. Класифікація даних у пролозі
- •1.4. Приклад доказу в пролозі
- •1.5. Подання задачі у вигляді і-або дерева
- •1.6. Структура програми в системі tp
- •1.7. Убудовані типи даних мови tp
- •1.8. Висновки
- •2. Підстави логічного програмування
- •2.1. Принцип резолюцій
- •2.3. Способи застосування принципу резолюцій
- •2.4. Диз’юнкти хорhа
- •3. Три семантичні моделі пролог-програми
- •4. Подання знань
- •4.1. Процес подання знань
- •4.2. Способи подання бази знань
- •4.2.1. Представлення цілісних інформаційних елементів у вигляді фактів
- •4.2.2. Подання атрибутів у вигляді фактів
- •4.2.3. Представлення знань у вигляді списку структур
- •4.2.4. Подання у вигляді рекурсивних структур
- •4.2.5. Подання у вигляді двійкового дерева
- •4.2.6. Порівняння різних виглядів подання бази даних
- •4.2.7. Компонування даних у список
- •4.3. Використання складених об'єктів
- •4.4. Використання альтернативних доменів
- •4.5. Засоби документування програми
- •4.6. Типи й властивості відношень предметної області
- •4.6.1. Обмеження, що забезпечують цілсність відношень
- •4.6.2. Властивості відношень бази знань і їхня підтримка в програмі на tp симетрія і асиметрія
- •Рефлексивность і нерефлексивность
- •Транзитивність
- •Симетричність і транзитивність
- •Спроба 1
- •Спроба 2.
- •Запам'ятовування списку відвіданих місць
- •4.7. Списки
- •4.7.1. Подання й зображення списків
- •4.7.2. Використання списків
- •4.7.3. Метод поділу списку на голову і хвіст (псгх)
- •4.7.4. Списки списків
- •Методи програмування
- •5.1. Повторення і відкіт (пв)
- •5.2. Метод відкоту після невдачі (впн)
- •5.3. Метод відсікання та відкоту (вв)
- •5.4. Повторення та рекурсія (пр)
- •5.5. Метод узагальненого правила рекурсії (упр)
- •5.6. Побудова рекурсивних структур методом прогресуючої підстановки (пп)
- •5.7. Предикат відсікання
- •5.8. Організація багаторазово виконуваних інтерактивних програм (бвіп)
- •5.9. Метод аналізу станів (ас)
- •5.10. Метод організації висхідних рекурсивних обчислень (вро)
- •5.11. Комбінація спадних і висхідних рекурсивных обчислень (ксвро)
- •5.12. Предикат fail-if (not)
- •5.13. Предикат true
- •5.14. Модифікація бази даних (мбд)
- •5.15. Керування базою даних (кбд)
- •5.16. Глобальні змінні (гз)
- •5.17. Накопичування результатів у базі даних за допомогою вимушеного відкоту і глобальної змінної (нрввгз)
- •5.18. Метапрограмування (мп)
- •Список рекомендованої літератури
- •1. Основи мови програмування пролог 4
- •2. Підстави логічного програмування 14
- •3. Три семантичні моделі пролог-програми 20
- •4. Подання знань 23
- •Програмування мовою пролог
Симетричність і транзитивність
Розглянемо особливості реалізації відношень, що є одночасно симетричними й транзитивними. Прикладом такго відношення може служити відношення “можна-проїхати”. Попередньо ми навчилися ці властивості забезпечувати окремо. Особлива складність при одночасному їх забезпеченні – можливість зациклення.
Спроба 1
Розглянемо реалізацію відношення “тснр_подорожувати1” (транзитивне, симетричне, нерефлексивне 1-а версія):
% при подорожі одним видом транспорту
тснр_подорожувати1(А, Б, м(Вид_транспорту, Б)):-
А <> Б,
сим_подорож(А, Б, Вид_транспорту).
% при подорожі більш, ніж одним видом транспорту
тснр_подорожувати1(А, Б, м(Вид_транспорту1, У, Вид_транспорту2)):-
А <> Б,
сим_подорож(А, У, Вид_транспорту1),
тснр_подорожувати1(У, Б, Вид_транспорту2).
Задамо приклад бази даних для транспортної мережі:
подорож(київ, кременчук, автобус).
подорож(київ, дніпропетровськ, зал_дорога).
Для забезпечення властивості симетричності додамо правило сим_подорож.
сим_подорож(А, Б, Вид_транспорту):-
подорож(А, Б, Вид_транспорту).
сим_подорож(А, Б, Вид_транспорту):-
подорож(Б, А, Вид_транспорту).
Тут “подорож” – це фактуальна база даних, що описує конкретні маршрути й види транспорту. Для спрощення в цій версії відсутні операнди з назвою транспортної компанії. Якщо ми введемо запит “тснр_подорожувати1(кременчук, дніпропетровськ, М)”, тобто захочемо довідатися, як можна проїхати від Кременчука до Дніпропетровська, то перша відповідь буде вірною:
М = м(автобус, київ, м(зал_дорога, дніпропетровськ))
Однак, виявиться, що існує нескінченна кількість відповідей, цінність яких дуже сумнівна:
М = м(автобус, київ, м(автобус, кременчук),
м(автобус, київ, м(зал_дорога, дніпропетровськ))
М = м(автобус, київ, м(автобус, кременчук),
м(автобус, київ, м(автобус, кременчук),
м(автобус, київ, м(зал_дорога, дніпропетровськ))
М = м(автобус, київ, м(автобус, кременчук),
м(автобус, київ, м(автобус, кременчук),
м(автобус, київ, м(автобус, кременчук),
м(автобус, київ, м(зал_дорога, дніпропетровськ)) та ін.
Тобто щоразу, коли ми запитуємо іншу відповідь, процедура робить ще один цикл між Києвом і Кременчуком, перш ніж дістанеться Дніпропетровська.
Спроба 2.
Можна уникнути циклічних переміщень між Києвом і Кременчуком, якщо зазначивши, що якщо існує прямий маршрут між пунктами А и Б, то не слід шукати які-небудь додаткові відповіді. Іншими словами, якщо перше правило процедури “тснр_подорожувати1” виявиться успішним, то необхідно заборонити застосовувати друге правило. Для цього можна застосовувати предикат “відсікання” (“!”). Перевіримо, чи усуне це виникнення циклічних переміщень:
% при подорожі одним видом транспорту
тснр_подорожувати2(А, Б, м(Вид_транспорту, Б)):-
А <> Б,
сим_подорож(А, Б, Вид_транспорту), !.
% при подорожі більш, ніж одним видом транспорту
тснр_подорожувати1(А, Б, м(Вид_транспорту1, У, Вид_транспорту2)):-
А <> Б,
сим_подорож(А, У, Вид_транспорту1),
тснр_подорожувати1(У, Б, Вид_транспорту2).
Якщо база даних про маршрути має той же вид, що й у попередній програмі, то відповідь на запит “тснр_подорожувати2 (кременчук, дніпропетровськ, М)” буде цілком достовірною
М = м(автобус, київ, м(жел_дорога, дніпропетровськ)).
Інтуїтивно ми уявляємо, що на цей запит повинна бути тільки одна відповідь, і програма її знаходить.
Але уявимо собі, що транспортна система має трохи трохи складний вигляд, наприклад, (рис. 11).
літак
зал_дорога
автобус автобус
автобус
автомобіль
автомобіль
Рис. 11. Схема транспортної мережі деякої компанії
Описати цю транспортну мережу мовою ПРОЛОГ можна в такий спосіб:
подорож(київ, кременчук, автобус).
подорож(київ, дніпропетровськ, зал_дорога).
подорож(кременчук, полтава, автомобіль).
подорож(полтава, дніпропетровськ, автобус).
подорож(київ, полтава, літак).
подорож(кременчук, черкаси, автомобіль).
подорож(київ, черкаси, автобус).
Результати виконання запиту “тснр_подорожувати2(кременчук, дніпропетровськ, М)” знову збентежують:
М = м(автобус, київ, м(зал_дорога, дніпропетровськ))
М = м(автобус, київ, м(літак, полтава), м(автомобіль, кременчук),
м(автобус, київ),м(зал_дорога, дніпропетровськ))
М = м(автобус, київ, м(літак, полтава), м(автомобіль, кременчук),
м(автобус, київ, м(літак, полтава), м(автомобіль, кременчук),
м(автобус, київ),м(зал_дорога, дніпропетровськ))
та ін.
Таким чином, додавання предиката “відсікання” дозволило усунути циклічні переміщення тільки для випадку, коли в базі даних “подорож” було всього два факти. Крім того, предикат “відсікання” небезпечний тим, що при його застосуванні можуть бути відкинуті й правильні відповіді. Якщо між двома пунктами курсує більше ніж один вид транспорту, то процедура “тснр_подорожувати2” стане циклічно переміщуватися між Кременчуком і Полтавою і ніколи не дійде до більш зручного маршруту з Кременчука на Дніпропетровськ через Київ.
Причиною цього є циклічність бази даних і запит “грузне” в одному з циклів. Існує два способи боротьби з таким поводженням програми:
1) необхідно ретельно перевіряти дані на відсутність циклів;
2) зробити програму нечуттєвою до циклічності даних.
Другий спосіб здається привабливішим. Можна зробити так, щоб процедура “тснр_подорожувати2” не поверталася в ті місця де вона вже побувала.