Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
48
Добавлен:
05.03.2016
Размер:
1.28 Mб
Скачать

6.1 Визначення поняття рекурсії

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

Для того, щоб завантажити N контейнерів, потрібно:

Якщо N=0, то зупинитися.

Якщо N>0, то завантажити один контейнер, потім завантажити ще N–1 контейнер.

Будемо вважати, що тут дано визначення процедури “завантаження N контейнерів”, де N – аргумент процедури і позначає деяке ціле число.

Дана процедура рекурсивна, тому що останній рядок – “завантажити N–1 контейнер” – є викликом процедурою самої себе. Слід відмітити, що аргумент при рекурсивному виклику простіший, ніж вихідний аргумент N, у тому розумінні, що (N–1) – це число менше, ніж число N. Тому “завантаження N контейнерів” є більш складний випадок, що виражається через менш складний випадок виконання тих же самих дій, тобто через “завантажити N–1 контейнер”.

Класичним прикладом рекурсивного визначення в Пролозі може бути процедура “предок”, що складається з двох правил:

предок(А, Б):-батько(А,Б).

предок(А, Б):-батько(В, Б), предок(А, В)

Сукупність цих правил визначає два способи, відповідно до яких одна особа (А) може бути предком іншої особи (Б).

Відповідно до першого правила, А є предком Б, якщо А – батько Б, тобто А є найближчим предком Б (рис.6.1,а).

Відповідно до другого правила А буде предком Б, якщо є дехто В, що, будучи батьком Б, має своїм предком А. Іншими словами, А – предок Б, якщо А – предок батька Б, тобто А – віддаленим предком Б (рис.6.1,б). У такий спосіб друге правило залежить від більш простої версії самого себе, тобто від підмети “предок”.

Рисунок 6.1 – Приклади відношення “предок” і його зв'язок з відношенням “батько”: а) А найближчий предок Б; б) А віддалений предок Б; в) приклад схеми програми.

Завдання 1.

У програму 5.2 введіть опис процедури “предок”. Виконайте ряд довільних запитів до програми. Використовуючи режим трасування, прослідкуйте послідовність обробки в Пролозі процедури “предок”. Збережіть програму у файлі “lab6.pro”

6.2 Склад рекурсивної процедури

Будь-яка рекурсивна процедура повинна включати принаймні по одній з перерахованих нижче компонент:

1. Нерекурсивна пропозиція (правило або факт), що визначає вихідний вид процедури, тобто вид процедури в момент, припинення рекурсії. Це, так називані, граничні умови.

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

Перша пропозиція процедури “предок” визначає вихідний вид процедури. Як тільки дана пропозиція стає істинною, подальша рекурсія припиниться. Тобто, перша пропозиція є граничною умовою.

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

Розглянемо ще один приклад побудови рекурсивної процедури для обчислення факторіала будь-якого цілого числа.

З визначення факторіала відомо, що 0!=1, а факторіал будь-якого числа N може бути обчислений як факторіал N–1, помножений на N. Це визначення є рекурсивним, оскільки зводить задачу знаходження N! до більш простої задачі знаходження факторіалу (N–1)! і потім множення отриманого значення на N.

Для позначення факту, що факторіал числа N рівний R, використовуємо предикат f(N, R). Його рекурсивне визначення буде мати вигляд, що приведений у програмі 6.1.

/* програма 6.1 */

predicates

f(integer,integer)

clauses

f(1,1) :-!.

f(N,R) :- M=N-1, f(M,V), R=V*N.

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

Реалізація виконання даної програми Пролог-системою для випадку обчислення факторіала числа 3 (тобто 3!) приведена на рис.6.2.

З рис.6.2, видно, що при виконанні заданої мети f(3,X) Пролог тричі звертається до процедури. При цьому перші два рази узгоджується друге правило, а на третьому кроці – перше. Особливість узгодження другого правила полягає в тому, що обидва рази виконання третьої підмети відкладається (заноситься в стек запитів) у вигляді рекурсії другої підмети. І тільки після узгодження на третьому кроці першого правила Пролог повертається до виконання третьої підмети. Вони послідовно, починаючи з останньої, витягаються зі стека запитів і виконуються.

Рисунок 6.2 – Схема виконання рекурсивної процедури f(N,R).

Завдання 2.

Використовуючи режим трасування, прослідкуйте послідовність обробки рекурсивних процедур на прикладі обчислення факторіала. Змініть програму таким чином, щоб вона обчислювала суму заданої послідовності цілих чисел. Налагодьте програму, а потім обчисліть суму першої тисячі чисел, суму перших 10 тисяч чисел. Який вийшов результат? Як його можна пояснити?