Організація повторюваних процесів

 

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

Існує два способи побудови правил, що виконують ту саму задачу кілька разів. Це повторення, що використовує повернення, і рекурсія, що використовує виклик процедури самої себе.

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

Але якщо цей підхід застосувати до предиката query тієї ж програми, тобто штучно викликати стан невдачі, додавши предикат fail у вигляді останньої підмети правила, то ніякого повторного запиту на введення ми не одержимо. Пояснюється це тим, що предикати вводу не є альтернативами, тобто не мають альтернативних рішень, а предикат do_answer() всі альтернативні рішення одержав, тобто мета query є істинною і рішення задачі закінчується.

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

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

repeat.

repeat :- repeat.

Перший рядок – це факт, що завжди успішний і забезпечує істинність предикату repeat. Але, оскільки для цього предиката існує ще одне правило, то покажчик відкату встановлюється на перший repeat. Другий рядок – це правило, що використовує самовиклик. Правило (другий repeat) викликає підмету (третій repeat), і цей виклик здійснюється успішно, тому що факт (перший repeat) відповідає підметі. Отже, правило також завжди успішне. Предикат repeat буде успішно обчислюватися при кожній новій спробі його викликати після відкату. Таким чином, repeat – це рекурсивне правило, що ніколи не буває неуспішним.

Введіть у програму 2.3 опис предикату repeat. Вставте звертання до цього предиката в якості першої підмети правила query. Запустіть на виконання програму.

Тепер з'явилася можливість повторного вводу, але немає ознаки закінчення і єдиний варіант виходу з програми – це Ctrl+Break. Але для того, щоб сформувати ознаку закінчення повторень, необхідно вияснити, як працює програма, і хто ініціює повтор. Першим виконується предикат repeat, що нічого не робить, далі – стандартні предикати, що не мають альтернатив, й останнім предикат do_answer, що і забезпечує відкат після невдачі до предикату repeat завдяки наявності в ньому предиката fail. Зверніть увагу, що наявність у програмі предикату repeat ще не забезпечує повторів, оскільки для організації повторів необхідне повернення до предикату repeat.

Але якщо відкат до repeat викликає do_answer, то він повинний і забезпечити, за певних умов, закінчення цього процесу. Якщо за умову виходу прийняти, наприклад, введення слова “stop” замість прізвища, то можна довизначити предикат do_answer ще одним правилом:

do_answer(X) :- X="stop", write("good bye").

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

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

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