You are on page 1of 14

ЛАБОРАТОРНА РОБОТА №6

Тема: Метод рекурсії. Метод відкату.

Ціль: Навчитися розробляти Пролог-Програми із застосуванням методу відсі-


кання та відкату, за допомогою методу повторення, бектрекінгу і рекурсії.
Час: 4 години.

4.1 Виконання роботи.


1) Вивчити теоретичні відомості;
2) Вивчити практичну частину;
3) Виконати самостійну роботу;
4) Відповісти на контрольні питання.

4.2 Теоретичні відомості.

4.2.1 Загальні відомості.


Дуже часто в програмах необхідно виконати ту саму завдання кілька разів. У
програмах на Турбо-Пролозі повторювані операції звичайно виконуються за
допомогою правил, які використовують відкат і рекурсію.
Існують два способи реалізації правил, що виконують одну й тугіше завдання
багаторазово. Перший їх вони будемо називати повторенням, а другий -
рекурсією. Правила Турбо-Прологу, що виконують повторення, використовують
відкат, а правила, що виконують рекурсію використовують самовиклик.
Вид правила, що виконує повторення, наступний:
repetitive_rule :- /* правило повторення */
<предикати й правила>,
fail. /* невдача */

Конструкція <предикати й правила> у тілі правила позначає предикати, що


містять кілька тверджень, а так само правила, певні в програмі. Убудований
предикат fail (невдача) викликає відкат, так що предикати й правила виконуються
ще раз.
Вид правила, що виконує рекурсію, наступний:
recursive_rule :- /* правило рекурсії */
<предикати й правила>,
recursive_rule.
Помітьте, що останнім правилом у тілі даного правила є саме правило
recursive_rule. Правила рекурсії містять у тілі правила самі себе.
Правила повтору й рекурсії можуть забезпечувати однаковий результат,
хоча алгоритми їхнього виконання не однакові. Кожний з них у конкретній
ситуації має свої переваги. Рекурсія, наприклад, може зажадати більше системних
ресурсів. Так щораз при рекурсивному виклику нові копії використовуваних
значень містяться в стек.
2
Стік являє собою область пам'яті, використовувану в основному для
передачі значень між правилами. Значення зберігаються поки правило не
завершитися або успішно, або неуспішно. У деяких ситуаціях таке використання
стека може бути виправдано, якщо проміжні значення повинні зберігатися в
певному порядку для подальшого використання.
Турбо-Пролог має засоби для скорочення "споживання" стека, однак
правила повтору, що використовують відкат, не збільшують зайняту частину
стека.
Звичайно ціль програми на Турбо-Пролозі містить одну або трохи підцілей,
які можуть бути або фактами, або правилами. Факт обчислюється негайно.
Результат буде або успішним, або неуспішним залежно від того, чи зіставимо
факт у програмі з фактом у правилі. Правило, будучи зв'язуванням підправив,
обчислюється шляхом обчислення підправив. Якщо підправило не може бути
успішно обчислено, то Турбо-Пролог виконує відкат, що б знайти інші можливі
шляхи обчислення цього підправила.

4.2.2 Метод відсікання й відкоту (ОО).


При програмуванні різних завдань зручно використовувати метод відкоту
після невдачі (МОПН) і метод відсікання й відкоту (ОО).
Відкат - це механізм, що Турбо-Пролог використовує для знаходження
додаткових фактів і правил, необхідних при обчисленні мети, якщо поточна
спроба обчислити мету виявилася невдалою.
Відкат є автоматичним инициируемым системою процесом, якщо не
використовуються засоби керування ім. Для керування процесом відкоту
передбачені два убудованих предикати: fail (невдача) - визначає, що поточний
пошук рішення для деякої подцели невдалий і потрібно почати новий пошук і
пердикат cut (або !) – примусово завершує всі пошуки (відсікання).
Наприклад, у деяких ситуаціях необхідно мати доступ тільки до певної
частини даних. Це буває, наприклад, коли запасні частини, що надійшли на склад,
вносяться в опис відразу ж після їхнього надходження, або коли заявки на них
фіксуються в довільному порядку. Метод відсікання й відкоту (ОО) може бути
використаний для фільтрації даних, обираних із тверджень бази даних.
Зручність цього методу стає більше явним при більшому числі умов для
вибірки. Для того, щоб з бази даних вибирати дані, що задовольняють деяким
умовам, необхідно мати засобу керування відкотом.
Для цих цілей Турбо-Пролог має убудований предикат cut (відсікання).
Предикат cut позначається символом знак оклику (!).
Цей предикат, обчислення якого завжди завершується успішно, змушує
внутрішні унификационные підпрограми "забути" всі покажчики відкоту,
установлені під час спроб обчислити поточну подцель.
Інакше кажучи, предикат cut "установлює бар'єр", що забороняє виконати
відкат до всіх альтернативних рішень поточної подцели. Однак наступні
подцели можуть створити нові покажчики відкоту, і тим самим створити умови
для пошуку нових рішень. Область дії предикат cut на них уже не поширюється.
3
Але якщо усе більше пізні цілі виявляться неуспішними, то бар'єр,
установлений предикатом cut, змусить механізм відкоту відітнути всі рішення в
області дії cut шляхом негайного відкоту до інших можливих рішень поза областю
дії cut.
Метод відсікання й відкоту використовує предикат fail для того, щоб
імітувати неуспішне обчислення й виконувати наступний відкат, доти, поки не
буде виявлена певна умова. Предикат cut служить для усунення всіх наступних
відкотів.
Деяка аналогія прояснить поняття відкоту.
Припустимо, що ваша мета - потрапити додому до друга, але ви не маєте
точного подання, як туди добратися. Однак ви знаєте, що після повороту з
автостради на перехресті необхідно згорнути праворуч. Друг живе в будинку
через дорогу від входу в парк.
Після того, як ви згорнете з автостради й повернете праворуч на першому
перехресті, ви не знайдете входу в парк. Тому ви повернетеся (виконаєте відкат)
до перехрестя й продовжите первісний рух до наступного перехрестя. Тут ви
знову повернете праворуч і пошукайте вхід у парк.
Якщо вам знову не вдасться знайти вхід у парк, ви ще раз повернетеся назад
(виконаєте відкат) і зробите спробу на наступному перехресті. Ви будете
повторювати цей процес доти, поки вам не вдасться досягти вашої мети знайти
будинок, або ж ви зазнаєте повної невдачі й відмовтеся від цієї витівки.
Турбо-пролог намагається обчислити мету за допомогою зіставлення терма
предиката й об'єктів мети з відповідними елементами у фактах і головах
правил. Зіставлення виконується ліворуч праворуч. Деякі підцілі ймовірно будуть
неуспішними при зіставленні з деякими фактами або правилами, тому Турбо-
Прологу потрібен спосіб "запам'ятовування крапок", у яких він може
продовжити альтернативні спроби знайти рішення. Перш ніж спробувати один з
можливих шляхів рішення підцілі, Турбо-Пролог фактично поміщає в програму
"покажчик". Покажчик визначає крапку, у яку може бути виконаний відкат, якщо
поточна спроба буде невдалою.
У міру того, як Турбо-Пролог успішно закінчує свої спроби обчислення
підцілей ліворуч праворуч, покажчики відкоту розставляються у всіх крапках, які
можуть привести до рішення.
Якщо деяка підціль виявляється неуспішної, то Турбо-Пролог відкочується
вліво й зупиняється в найближчого покажчика відкоту. Із цієї крапки Турбо-
Пролог починає спробу знайти інше рішення для неуспішної мети.
Доти, поки наступна мета на даному рівні не буде успішної, Турбо-Пролог
буде повторювати відкат до найближчого покажчика відкоту. Ці спроби
виконуються внутрішніми підпрограмами уніфікації й механізмом відкоту.
Остаточним результатом буде або успішне, або неуспішне обчислення мети.

4.2.3 Метод повторення (МП).

МП-Метод, як і ОО-Метод, використовує відкат. Але в МП-Методі виконати


відкат можливо завжди у відмінності від ОО-Методу.
4
В ОО-Методі - відкат виконуються тільки після штучного створеного
неуспішного результату. Правило рекурсії загального виду має складну структуру
і є узагальненням цих методів.
Вид правила повтору, обумовленого користувачем, що випливає:
repeat. /* повторити */
repeat :- repeat.
Перший repeat є твердженням, який повідомляє що предикат є repeat
істинним. Перший repeat не створює підцілей, тому дане правило завжди
успішно. Однак, оскільки є ще один варіант для цього правила, то покажчик
відкоту встановлюється на перший repeat. Другий repeat - це правило, що
використовує саме себе як компоненту (третій repeat). Другий repeat викликає
третій repeat, і цей виклик обчислюється успішно, тому що перший repeat
задовольняє подцели repeat. Отже, правило repeat так само завжди успішно.
Предикат repeat буде обчислюватися успішно при кожній новій спробі його
викликати після відкоту. Факт у правилі буде використовуватися для виконання
всіх подцелей програми. Таким чином, repeat це рекурсивне правило, що ніколи
не буває невдалим.
Подібним чином у МП-Правилі можна використовувати більше одного
правила повтору.

4.2.4 Бектрекінг, кон’юнкція та диз'юнкція.


Бектрекінг (алгоритм пошуку з поверненням) - механізм повернення, що
здійснює відкат програми до тої крапки, у якій вибирався уніфікований з
останньої підцілью діз’юнкт (елемент предиката). Для цього крапка, де вибирався
один з можливих уніфікованих з підцілью діз’юнктів, запам'ятовується в
спеціальному стеці, для наступного повернення до неї й вибору альтернативи у
випадку невдачі. При відкоті всі змінні, які були зазначені в результаті уніфікації
після цієї крапки, знову стають вільними.
У підсумку виконання програми може завершитися невдачею, якщо одну з
підцілей не вдалося уніфікувати з жодним диз’юнктом програми, і може
завершитися успішно, якщо був виведений порожній діз’юнкт, а може й просто
зациклитися.
Турбо-Пролог має убудований механізм логічного висновку, завдяки чому
від користувача потрібно тільки опис свого завдання за допомогою апарата логіки
предикатів першого порядку, а пошук рішення система бере на себе. Розглянемо
приклад використання бектрекінга в Турбо-Пролозі:
p :- q,s.
p :- r,t.
Цю програму можна прочитати в такий спосіб. При виконанні процедури p
виконуються процедури q і s. Якщо вони завершуються успішно, то й процедура
p уважається успішно завершеною. Якщо це не так, то виконуються процедури r
і t. У цьому випадку процедура успішно завершується, якщо r і t завершені
успішно. У противному випадку процедура p зазнає невдачі. Цей процес
повернення до пошуку інших рішень називається бектрекінгом (backtracking).
5
Принципова різниця між backtracking і рекурсією полягає в тім, що перший
не дозволяє передавати дані між кроками ітерацій, тому що щораз при досягненні
мети всі змінні "звільняються".
При створенні програм у Турбо-Пролозі також часто користуються
кон’юнкцієй (логічне множення) і диз'юнкцією (логічне додавання):
1) Якщо як умова A виступає факт, або кілька фактів A1,...,AN, з'єднані
логічною операцією И:
A1 И A2 И ... І AN.
те в математичній логіці таке вираження називається кон’юнкцієй.
Воно вважається щирим у тому випадку, якщо щирі всі його компоненти.
2) Якщо як умова A виступає факт, або кілька фактів A1,...,AN, з'єднані
логічною операцією АБО:
A1 АБО A2 АБО ... АБО AN.
те в математичній логіці таке вираження називається диз'юнкцією.
Диз'юнкція – це коли підцелі поставлені як альтернативні, тобто якщо кілька
виражень, відповідають тому самому правилу. Турбо-Пролог буде шукати будь-
які рішення, відповідно одній з підцелей.

4.2.5 Методи організації рекурсії.


4.2.5.1 Проста рекурсія.
Правило, що містить саме себе як компонент, називається правилом
рекурсії. Правила рекурсії так само як правила повтору реалізують повторне
виконання завдань. Вони досить ефективні, наприклад, при формуванні запитів
до бази даних, а також при обробці таких доменних структур, як списки. Приклад
правила рекурсії:
write_srting :- /* видати рядок */
write("МИ - ЦЕ УВЕСЬ СВІТ"), nl, write_string.

Це правило складається із трьох компонентів. Перші дві видають рядок


"МИ - ЦЕ УВЕСЬ СВІТ" і переводять курсор на початок наступного рядка
екрана. Третя - це саме правило. Тому що воно містить саме себе, те щоб бути
успішним, правило write_string повинне задовольняти саме собі. Це приводить
знову до виклику операції видачі на екран рядка й зсув курсору на початок
нового рядка екрана. Процес триває нескінченно й у результаті рядка видається
на екран нескінченне число раз.
Однак у випадку виникнення нескінченної рекурсії число елементів даних,
використовуваних рекурсивним процесом, безупинно росте й у деякий момент
стік переповниться. На екрані з'явиться повідомлення про помилку. Виникнення
переповнення під час виконання програми для користувача небажано, тому що в
результаті можуть виявитися загубленими істотні дані.
Уникати подібні ситуації можна збільшенням розмірів стека, для чого
служить опція Miscellaneous settings (інші установки параметрів) у меню Setup
(установка). Якщо рекурсивне правило не генерує покажчиків відкоту й остання
підцель правила є рекурсивним викликом самого правила, то Турбо-Пролог
6
усуне додаткові витрати, викликувані рекурсією. Цей процес називається
усуненням хвостової рекурсії.
Уникнути виникнення нескінченної рекурсії можна. Для цього варто
ввести предикат завершення, що містить умова виходу. Формулювання умови
виходу російською мовою для правила write_string можуть мати вигляд:
"Продовжувати печатка рядка доти, поки лічильник печатки не перевищить
число 7. Після чого зупинити процес". Визначення умов виходу й включення їх
у правило рекурсії є дуже важливим елементом програмування на Турбо-Пролозі.

4.2.5.2 Метод узагальненого правила рекурсії (УПР).


Узагальнене правило рекурсії містить у тілі правила саме себе. Рекурсія
буде кінцевої, якщо в правило включена умова виходу, що гарантує закінчення
його роботи. Тіло правила складається із тверджень і правил, що визначають
завдання, які повинні бути виконані.
Нижче в символічному виді даний загальний вид правила рекурсії:
<ім'я правила рекурсії> :-
<список предикатів>, (1)
<предикат умови виходу>, (2)
<список предикатів>, (3)
<ім'я правила рекурсії>, (4)
<список предикатів>. (5)
Хоча структура цього правила складніше, ніж структура простого правила
рекурсії, розглянутого в попередньому розділі, однак принципи, застосовувані до
першого з них застосовні й до другого.
Дане правило рекурсії має п'ять компонентів. Перша - це група предикатів.
Успіх або невдача кожного з них на рекурсію не впливає. Наступний компонент -
предикат умови виходу. Успіх або невдача цього предиката або дозволяє
продовжити рекурсію, або викликає її зупинку. Третій компонент - список інших
предикатів. Аналогічно, успіх або невдача цих предикатів на рекурсію не робить
впливу. Четверта група - саморекурсивне правило. Успіх цього правила викликає
рекурсію. П'ята група - список предикатів, успіх або невдача яких не впливає на
рекурсію. П'ята група також одержує значення (якщо вони є), поміщені в стек під
час виконання рекурсії.
Правило рекурсії повинне містити умова виходу. У противному випадку
рекурсія нескінченна й правило даремно. Відповідальність за забезпечення
скінчення правила рекурсії лежить на програмісті. Правила, побудовані
зазначеним образом, є узагальненими правилами рекурсії (УПР), а метод
називається УПР-Методом.
Наприклад, ви хочете написати правило генерації всіх цілих чисел
починаючи з 1 і кінчаючи 7. Нехай ім'я правила буде
write_number(Number).
Для цього приклада перший компонент структури загального правила
рекурсії не використовується. Другим компонентом, тобто предикатом виходу, є
Number < 8. Коли значення Number дорівнює 8, правило буде успішним і
7
програма завершиться. Третій компонент правила оперує із числами. У цій
частині правила число видається на екран і потім збільшується на 1.
Для збільшеного числа буде використовуватися нова змінна Next_Number.
Четверта компонента - виклик правила рекурсії write_number(Next_number).
П'ятий компонент, представлений у загальному випадку, тут не використовується.

4.3 Практична частина.

4.3.1 Розглянемо приклад програми й проаналізуємо поняття відкоту на


прикладі даних про спортивні захоплення, що містить наступні факти:

plays(tom,football) /* Том грає в американський футбол*/


plays(john,soccer) /*Джон грає в європейський футбол*/
plays(john,volleyball) /* Джон грає у волейбол*/
plays(tom,basketball) /* Том грає в баскетбол*/
plays(tom,volleyball) /* Том грає у волейбол */
plays(john,baseball) /* Джон грає в бейсбол*/

Завдання програми визначити в яку гру одночасно грають Джон і Том.


Твердження мети наступне:
plays(john,G),plays(tom,G).
Помітьте, що ця мета є зв'язування двох підцілей. Кожна підціль містить
змінну G. Завдання полягає в знаходженні значення для G, що задовольняє обом
підцілям. Щоб обчислити першу підцель plays(john,G), Турбо-Пролог шукає в
базі даних порівнянне твердження.
Перший об'єкт твердження lays(john,soccer) зіставимо з першим об'єктом
першої підцілі, так що подцель успішно обчислюється й змінна G одержує
значення soccer. Існують інші твердження для plays, які можуть бути використані
для обчислення цієї ж підцілі. Тому Турбо-Пролог повинен зберегти слід цих
тверджень на випадок неуспішного обчислення другий підцілі зі значенням G
рівним soccer. Для цього внутрішні уніфіковані підпрограми встановлюють
покажчик відкоту на крапку, з якої можуть бути продовжені зусилля по
обчисленню першої підцілі.
Тепер Турбо-Пролог намагається обчислити другу підціль. Тому що G має
значення soccer, те ця подцель є plays(tom,soccer). Турбо-Пролог переглядає базу
даних у пошуку твердження, порівнянного із цієї подцелью. Порівнянних
тверджень ні, тому підціль неуспішна.
Тому що друга підціль обчислена неуспішно, те Турбо-Пролог знову повинен
почати перегляд з першої підцілі. Після того, як спроба обчислити другу подцель
виявилася неуспішної, змінна G звільняється і Турбо-Пролог знову починає
пошук твердження для обчислення підцілі plays(john,G).
Якби ціль у цьому прикладі була внутрішньої, то процес обчислення
зупинився б після першого її успішного обчислення. Однак ціль тут зовнішня,
тому процес повторюється доти, поки не будуть знайдені всі успішні способи
обчислення мети.
8
Але інформація, що втримується в даних твердженнях, дає тільки одне
припустиме значення для G, що задовольняє обом підцілям, тобто результат
обчислення підцілі є G=volleyball.

4.3.2 Розглянемо приклад програми використання методу ОО.


Метод відкоту й відсікання (ОО) демонструє проста ситуація, у якій
предикати бази даних містять кілька імен, як це має місце для предикатів child
(дитина) у програмі розташованої нижче й формуючий список імен дітей.
domains
person = symbol

predicates
child(person)
show_some_of_them
make_cut(person)
goal
write("Хлопчики й дівчинки"),
nl, nl,
show_some_of_them

clauses
child("Tom ").
child("Beth ").
child("Jeff ").
child("Sarah ").
child("Larry ").
child("Peter ").
child("Diana ").
child("Judy ").
child("Sandy ").

show_some_of_them :-
child(Name),
write(" ", Name), nl,
make_cut(Name),!.

make_cut(Name) :-
Name="Diana".

Припустимо, що необхідно видати список імен до ім'я Diana включно.


Предикат cut виконає відсікання в зазначеному місці. Предикат fail
використовується для продовження відкотів і доступу до послідовності імен
бази даних до елемента з ім'ям Diana.
Таким чином, поставлену завдання виконує відповідна комбінація
предикатів cut і fail. Ця комбінація називається методом відкоту й відсікання
9
(ОО). Програма, що формує список імен дітей демонструє цей метод. У програмі
про імена предикатом бази даних є child(person). Для цього предиката є 9
альтернативних тверджень. Правило, що забезпечують генерацію всіх імен (а не
тільки деяких) має вигляд:
show_them_all :-
child(Name),
write(" ", Name), nl,
fail.

Воно засновано на методі ОПН. При цьому для того, що б використовувати


предикат cut, необхідно визначити деяку умову, що може бути й простим, як у
нашім прикладі, і дуже складним. У цьому випадку достатнім є умова
Name=Diana. Правило, що визначає, ця умова має вигляд:
make_cut(Name) :-
Name="Diana".

Це правило з наступним предикатом cut (!) утворить правило make_cut


(зробити відсікання). Тепер виконання програми буде неуспішним, а відкоти
будуть повторюватися доти, поки Name не виявиться рівним Diana. У цей момент
результат виконання правила make_cut буде успішним, що у свою чергу, викличе
виконання предиката cut. Таким чином, комбінуючи правила відсікання з методом
УПН, можна одержати ОО-Правило:
show_some_of_them :-
child(Name),
write(" ", Name), nl,
make_cut(Name),!.
make_cut(Name) :-
Name="Diana".

Ви можете змінити видачу програми, змінивши ім'я об'єкта в умові


відсікання. Наприклад, Nameѕth, видає список імен до ім'я Beth включно. Цей
спосіб використання ОО-Методу називається методом ранжируваного відсікання.

4.3.3 Розглянемо приклад програми використання методу ОПР.


Метод узагальненого правила рекурсії (ОПР) проілюструємо на прикладі
програми генерації ряду чисел.
write_number(8).
write_number(Number) :-
Number < 8,
write(Number), nl,
Next_Number = Number + 1,
write_number(Next_number).
Програма починається зі спроби обчислити подцель write_number(1).
Спочатку програма зіставляє подцель із першим правилом write_number(8). Тому
що 1 не дорівнює 8, то зіставлення неуспішно. Програма знову намагається
10
зіставити подцель, але вже з головою правила write_number(Number). Цього разу
зіставлення успішно внаслідок того, що змінної Number привласнено значення 1.
Програма порівнює це значення з 8; ця умова виходу. Тому що 1 менше 8, то
підправило успішно. Наступний предикат видає значення, привласнене Number.
Змінна Next_Number одержує значення 2, а значення Number збільшується 1.

4.3.4 Використання рекурсії.


Важлива властивість правила рекурсії складається в його розширюваності.
Наприклад, воно може бути розширене для підрахунку суми ряду цілих чисел.
Нижчеподана програма використовує правило рекурсії для обчислення суми
ряду цілих чисел від 1 до 7:
S(7) = 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28 або
S(7) = 7 + 6 + 5 + 4 + 3 + 2 + 1 = 28
Правило рекурсії виконує обчислення за звичайною схемою додавання:
1 Початкове значення
+2 Наступне значення

3 Часткова сума
+3 Наступне значення

6 Часткова сума....
...
Тоді частина програми, що використовує правило рекурсії буде мати вигляд:
sum_series(1,1). /* сума ряду */
sum_series(Number,Sum) :-
Number > 0,
Next_number = Number - 1,
sum_series(Next_number, Partial_Sum),
Sum = Number + Partial_Sum.

Дане правило має 4 компоненти й одне додаткове нерекурсивне правило. Тут


останній компонент правила рекурсії - це правило Sum з Partial_Sum (часткова
сума) у якості змінної. Це правило не може бути виконане доти, поки Partial_Sum
не одержить деякого значення.
А сама програма використання рекурсивного предиката для знаходження
суми S(N) ряду, де N - позитивне ціле число, при N=7 буде мати вигляд:
domains
number, sum = integer

predicates
sum_series(number, sum)
goal
sum_series(7,Sum),
write("Сума ряду:"),nl,nl,
write(" S(7) = ", Sum), nl.
11
clauses
sum_series(1,1). /* сума ряду */
sum_series(Number,Sum) :-
Number > 0,
Next_number = Number - 1,
sum_series(Next_number, Partial_Sum),
Sum = Number + Partial_Sum.

Програма Сума ряду 1 починається зі спроби виконати підціль


sum_series(7,Sum). Спочатку програма намагається зіставити підціль із
подправилом sum_series(1,1). Зіставлення невдало. Потім вона намагається
зіставити підціль із sum_series(Number,Sum). Цього разу зіставлення
завершується успішно із присвоєнням змінної Number значення 7. Потім програма
порівнює значення Number, що дорівнює 7, з 0, тобто перевіряється умова
виходу. Тому що 7 більше 0, то зіставлення успішно, програма переходить до
наступного підправилу.
Для цього підправила змінної Next_number привласнена значення 6, тобто
значення Number - 1. Потім правило викликає саме себе у вигляді
sum_series(6,Partial_Sum). Наступної підправилом є правило Sum, що містить
вільну змінну Partial_Sum. Тому що тільки що був викликаний рекурсивний
процес, те правило Sum не може бути викликано.
Тепер програма намагається зіставити незмінне правило sum_series(1,1) з
sum_series(6,Partial_Sum). Процес зіставлення неуспішний, оскільки
непорівнянно жоден з параметрів. У результаті програма переходить до
наступного правила з головою sum_series(Number,Sum), привласнюючи змінної
Number значення 6.
Цей циклічний процес зіставлення триває доти, поки не буде отримане
sum_series(1,Partial_Sum). Тепер це правило зіставляється з sum_series(1,1), а
Partial_Sum приписується значення 1. При зіставленні правила з головою
правила змінна Sum одержує значення 1. Тому що зіставлення триває далі, те
Next_number одержує значення 0 ( 1-1). При наступному циклі зіставлення змінна
Number одержує значення 0. Під час зіставлення з умовою виходу правило
виявляється неуспішним, і зіставлення "стрибає" до правила Sum.
Під час процесу зіставлення змінна Partial_Sum була вільна, а програма
запам'ятовувала значення Number для наступного використання. Але це правило
продовжує означивати змінну Sum, привласнюючи їй послідовно значення 1, 3,
6, 10, 15, 21 і 28. Кінцеве значення Sum є 28.
12
4.4 Самостійна робота.

4.4.1 Використовуючи предикат fail і метод ОПН створіть програму яка


перераховує й виводить на екран назви будь-яких десяти міст США.
4.4.2 Створіть програму побудови рекурсивних правил для уведення й
висновку будь-яких символів уводяться із клавіатури. У створюваній програмі
символом # створіть (позначте) процедуру завершальну роботу програми.
4.4.3 Використовуючи рекурсію створіть програму яка проводить генерацію
ряду чисел від 1 до 8 у порядку зростання.
4.4.4 Змінить вищенаведену програму (4.1.2) генерації ряду чисел так, щоб
вона видавала всі цілі числа від 53 до 62.
4.4.5 Змінить підціль і правило рекурсії програми (4.1.2) генерації ряду
чисел так, щоб результатом програми була генерація цілих чисел від 1 до 7 у
порядку убування.
4.4.6 Використовуючи рекурсивний предикат і предикат відсікання (!)
створіть програму для знаходження суми S(N) ряду чисел, де N - позитивне ціле
число. Визначите суму ряду при N=20.
4.4.7 Використовуючи рекурсію й предикат відсікання (!) створіть програму
для обчислення факторіала N! позитивного числа N. Визначите факторіал при
N=25.

4.5 Контрольні питання.

1) Дайте визначення поняттю відкат.


2) У чому полягає метод відсікання та відкату?
3) Суть методу повторення?
4) Що таке бектрекінг?
5) Дайте визначення поняттю кон’юнкція?
6) Дайте визначення поняттю диз'юнкція?
7) Що таке рекурсія?
8) У чому полягає метод простої рекурсії?
9) У чому полягає метод узагальненого правила рекурсії?
13

СПИСОК ЛІТЕРАТУРИ

1. Марселлус Д. Программирование экспертных систем на Турбо-Прологе.


- М.: Финансы и статистика, 1994. – 280 с.
2. Ин Ц., Соломон Д. Использование Турбо-Пролога. Пер. с англ.
Кондратьева О.Л., Буланже Д.Ю. Под. ред. Сушкова Б.Г. –М.:. Мир, 1990, - 564 с.
3. Тарков М.С. Программирование на Турбо-Прологе. – Новосибирск, 1999.
– 66 с.
4. Ин Ц., Соломон Д. Использование Турбо-Пролога. Пер. с англ.
Кондратьева О.Л., Буланже Д.Ю. Под. ред. Сушкова Б.Г. –М.:. Мир, 1993. - 608 с.
5. Братко И. Программирование на языке Пролог для искусственного
интеллекта. - М.: Мир, 1990. – 560 с.
6. Стерлинг Л., Шапиро Э. Искусство программирования на языке Пролог.
– М.: Мир, 1990. – 235 с.
7. Клоксин У., Меллиш К. Программирование на языке Пролог. –М.: Мир,
1988. – 420 с.
14

You might also like