- •Міністерство освіти і науки України Дніпропетровський національний університет
- •Програмування мовою пролог
- •Дніпропетровськ
- •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
- •Програмування мовою пролог
4.7.2. Використання списків
Списки дуже важливі при програмуванні на ПРОЛОЗі. Списки дозволяють працювати з набором об'єктів довільної довжини як із єдиним цілим. При цьому важливий порядок розташування таких об'єктів у списку. Списки можуть складатися з чисел, символів, рядків, довільних структур і т.ін. Якщо компонентами списку постають списки, то можна говорити про списки списків. Причому ці списки можуть містити елементи різних типів.
Зокрема, списки можуть застосовуватися для подання алгебраїчних матриць:
a b c d
A = e f g h .
i j k l
Тоді на ПРОЛОЗі цю матрицю можна подати у вигляді
A = [ [ a, b, c, d], [e, f, g, h], [i, j, k, l] ].
Щоб використовувати списки в програмі на TP, насамперед необхідно описати списковий доменний тип. Без цього не можна буде визначити жодного предиката бази даних, що зберігає ці списки або програмні предикати, які обробляють списки.
Наприклад, нехай у нас будуть списки трьох виглядів: списки цілих, списки дійсних чисел і списки тварин. Для цього знадобляться такі описи:
DOMAINS
список_цілих = integer *
список_дійсних = real *
список_тварин = symbol *
Як видно, символ “*” застосовується для задання спискового доменного типу.
Тепер необхідно подбати про збереження таких списків у програмі. Списки можуть зустрічатися в програмі тільки як компоненти структури або цілі. Це означає, що безпосередньо в розділі CLAUSES списки зустрічатися не можуть. Визначимо кілька предикатів бази даних, що зберігають наші списки:
DATABASE
цілі(список_цілих)
дійсні(список_дійсних)
тварини(список_тварин)
Тепер у розділ CLAUSES можна помістити конкретні екземпляри цих списків.
CLAUSES
цілі( [1, 5, 7] ).
дійсні( [3.2, 4.6, 5.7, 1.5] ).
тварини( [кішка, собака, кінь] ).
Дістати списки з бази даних ПРОЛОГу можна за допомогою задання цілей (запитів). Наприклад.
GOAL
цілі(Список_Усіх),
дійсні([Перше, Друге, Третє, _ ]),
тварини([ _ , Друга_тварина, _ ]).
Відповідями на цей запит будуть такі конкретизації змінних:
Список_Усіх = [ 1, 5, 7 ]
Перше = 3.2
Друге = 4.6
Третє = 5.7
Друга_тварина = собака
Так
Слід звернути увагу, що якщо якийсь компонент списку непотрібний, необхідно його замінити анонімною змінною. Адже не можна в запиті зіставити список із трьох елементів зі списком з чотирьох.
Для обробки списків необхідно описати програмний предикат у розділі PREDICATES. Наприклад, опишемо предикати друку списків:
PREDICATES
друк_цілих( список_цілих)
друк_вещ(список_вещ)
друк_тварин(список_тварин)
Потім у розділі CLAUSES можна помістити визначення цих предикатів. Тут є одна складність. Вона полягає в тому, що в попередньому прикладі ми отримували списки з бази даних ПРОЛОГу за допомогою запитів, у яких була відома кількість компонентів у кожному списку. Але списки цінні саме тим, що вони можуть містити невизначену кількість компонентів. Нам потрібний спосіб обробки таких списків. Якщо ми не знаємо, яку кількість компонентів містить в список, то їх треба викликати й обробляти по одному.
4.7.3. Метод поділу списку на голову і хвіст (псгх)
Природно обробляти списки, починаючи з голови. Для поділу списку на голову і хвіст можна використати символ “|”. Якщо зіставити список [Head | Tail] з іншим списком, то Head одержить значення елемента, що розташований у голові списку, а Tail – значення хвоста. Слід зазначити, що ціль [Head | Tail] може зіставитися тільки з непорожнім списком. Тому наша процедура друку списку повинна складатися мінімум із двох тверджень. Одне твердження буде визначати наші дії для порожнього списку, а інше – для непорожнього:
CLAUSES
друк_списку( [ ] ).
друк_списку( [Head | Tail] ):-
write(Head), nl,
друк_списку( Tail ).
Завдяки тому, що хвіст списку (Tail) є список, його можна обробити за допомогою цієї ж процедури (з використанням рекурсії). Оскільки операція поділу списку на голову і хвіст може застосовуватися до списків, що містять елементи різного доменного типу, то немає необхідності реалізовувати кілька предикатів для друку списків різних доменних типів. Але описати їх у розділі PREDICATES необхідно з указівкою всіх доменних типів:
PREDICATES
друк_списку(список_цілих)
друк_списку(список_дійсних)
друк_списку(список_тварин)
Такі процедури, аргументами яких можуть бути об'єкти різних типів, у програмуванні прийнято називати поліморфними процедурами. Процедура друк_списку є саме така поліморфна процедура ще й тому, що предикат write у мові TP також є поліморфним.
Поцедура друку списку реалізувалась рекурсивно. І це невипадково. Визначення списку є також рекурсивне. А для рекурсивних структур даних найбільш природний спосіб обробки – рекурсія. Для TP рекурсія до того ж і єдиний можливий спосіб обробки таких структур.