- •Міністерство освіти і науки України Дніпропетровський національний університет
- •Програмування мовою пролог
- •Дніпропетровськ
- •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
- •Програмування мовою пролог
5.11. Комбінація спадних і висхідних рекурсивных обчислень (ксвро)
Задача. Скласти процедуру, що виконує вирівнювання списку з підсписками (вирівнювання списку полягає в виведенні всіх елементів вихідного списку на один рівень):
вирівнювання(вихідний_список, вирівняний_список)
Ціль: вирівнювання([2, [1, 3], [4]], F).
F = [2, 1, 3, 4].
Ціль: вирівнювання([[2, 4], [ ], [1], 3], F).
F = [2, 4, [ ], 1, 3].
Передамо всю роботу по вирівнюванню вихідного списку допоміжній процедурі приховане_вирівнювання (використовує висхідну рекурсію):
вирівнювання(L, F):-
приховане_вирівнювання(L, [ ], F).
Процедуру приховане_вирівнювання будемо розробляти методом аналізу станів.
Етапи:
1. Вигляділення трьох станів:
а) вихідний список – порожній;
б) вихідний список – непорожній, і головою вихідного списку також постає список;
в) вихідний список – непорожній і головою списку постає деякий елемент –не список.
2. Розпізнання станів за допомогою аргументів, що мають такий вигляд:
а) [ ];
б) [ [H | T] | L];
в) [H | T].
3. Реалізація поводження процедури в цих станах у такий спосіб:
а) фактом
приховане_вирівнювання([ ], [ ]).
% Якщо перший список порожній, то й результатом буде
% порожній список
б) другий стан викликає основні труднощі. Ми не можемо помістити об'єкт H у голову вихідного списку, оскільки він сам може бути списком. Тому тільки висхідна рекурсія не може служити адекватним методом розв’язання цієї задачі. Але можна застосувати комбінований підхід, об'єднавши спадну рекурсію з висхідною. Це можна реалізувати за допомогою правила
приховане_вирівнювання([ [H | T] | L], S, F):-
приховане_вирівнювання(L, S, Вирівн),
приховане_вирівнювання([H | T], Вирівн, F).
% Додатковий аргумент S дає список, вирівняний до
% даного моменту. При першому виклику – це порожній
% список. Перша підціль тіла правила дає список Вирівн, що
% містить елементи вирівняного списку L, поміщені в початок
% списку S. Друга підціль, використовуючи список Вирівн як
% вхідний, дописує до нього на початок результат
% вирівнювання списку [H | T], одержуючи результуючий
% список F.
в) У третьому стані об'єкт H буде додан у голову вихідного списка, а хвіст вихідного списку буде будуватися за допомогою рекурсивного виклику (спадна рекурсія з прогресуючою підстановкою):
приховане_вирівнювання([H | T], S, [H | L]):-
приховане_вирівнювання(T, S, L).
4. Розташування тверджень у такому ж порядку. Одержимо:
вирівнювання (L, F):-
приховане_вирівнювання(L, [ ], F).
приховане_вирівнювання([ ], [ ]).
приховане_вирівнювання([[H | T] | L], S, F):-
приховане_вирівнювання(L, S, Вирівн),
приховане_вирівнювання([H | T], Вирівн,F).
приховане_вирівнювання([H | T], S, [H | L]):-
приховане_вирівнювання(T, S, L).
Проілюструємо поводження цієї процедури на прикладі вирівнювання списку [[2, 4], [ ], [1], 3] (рис. 20).
Ціль: вирівнювання([[2, 4], [ ], [1], 3], F).
Вхідний список [[2, 4], [ ], [1], 3]
(перший аргумент)
Допоміжний список: [ ] Вхід Результуючий список [2, 4, [ ], 1, 3]
(другий аргумент)
[ ] Вихід
(Третій аргумент
2 у базовому стані )
[ ]
4
1 [ ] 3 [ ]
Рис. 20. Вирівнювання списку з підсписками
Вирівнювання цього списку можна подати у вигляді обходу дерева:
[ ] - позначає вершину, у якій досягається базовий стан;
- позначає вершину, у якій досягається другий стан (перший елемент списку являє собою список);
- позначає вершину, у якій досягається третій стан (перший елемент списку не є список).
Дана процедура обходить дерево у зворотному порядку, тобто за формулою П-Л-К (Праве – Ліве – Корінь). Якщо ліва і права гілки, що ростуть із вершини, самі – дерева, тоді першим обходиться праве піддерево (стан 2). Якщо ліва гілка – лист, то вона формує частину вихідного списку, що знаходиться в голові того списку, який формується при обході правого піддерева (стан 3).
На жаль, хоча дана процедура й повертає правильний результат
Ціль: вирівнювання([[2, 4], [ ], [1], 3], F).
F = [2, 4, [ ], 1, 3]
при активізації відкоту, вона буде видавати й неправильні альтернативні відповіді:
F = [2, 4, [ ], [1], 3]
F = [[2, 4], [ ], 1, 3]
F = [[2, 4], [ ], [1], 3]
Це відбувається тому, що наша процедура не забезпечує винятковості окремих станів. Тобто ми не виконали п'ятий етап методу аналізу станів. Проте серед усіх відповідей, обов'язково одна (перша) буде правильна. Але при розробці процедури необхідно проаналізувати всі аспекти її поводження (у тому числі й при відкоті). Тому займемося цим питанням.
Перший стан ніяких питань не викликає: він є винятковим стосовно другого і третього. Але список, форма якого [H | T] не виключає і списку з формою [ [H | T] | L]. Іншими словами, список, узгоджений зі зразком [ [H | T] | L], буде узгоджений і зі списком [H | T]. Нам необхідний якийсь механізм, що не допускав би того, щоб у третьому стані змінна H відповідала непорожньому списку. Це можна реалізувати за допомогою сторожової цілі
H <> [ _ | _ ]
доданої до твердження для третього стана.
От тепер ми одержимо кінцевий результат нашої задачі:
вирівнювання (L, F):-
приховане_вирівнювання(L, [ ], F).
приховане_вирівнювання([ ], [ ]).
приховане_вирівнювання([ [H | T] | L], S, F):-
приховане_вирівнювання(L, S, Сглаж),
приховане_вирівнювання([H | T], Сглаж, F).
приховане_вирівнювання([H | T], S, [H | L]):-
H <> [ _ | _ ],
приховане_вирівнювання(T, S, L).
Можна забезпечити винятковість другого й третього стану процедури за допомогою відсікання. Це даст такий варіант реалізації процедури “вирівнювання”:
вирівнювання (L, F):-
приховане_вирівнювання(L, [ ], F).
приховане_вирівнювання([ ], [ ]).
приховане_вирівнювання([[H | T] | L], S, F):-!,
% це відсікання постачає третє твердження неявною сторожовою
% ціллю
приховане_вирівнювання(L, S, Вирівн),
приховане_вирівнювання([H | T], Вирівн, F).
приховане_вирівнювання([H | T], S, [H | L]):-
% H <> [_|_], - тепер ця сторожова ціль непотрібна
приховане_вирівнювання(T, S, L).