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

2.3 Пошук з поверненням при виконанні Пролог-програм

Знання про метод пошуку з поверненням, що реалізований в Пролог-системі, дозволяє правильно складати Пролог-програми і керувати пошуком рішень.

Вирішуючи будь-яку задачу. Пролог будує дерево підзадач, відзначає, які підзадачі вирішені, а які ще ні. При вирішенні будь-яких підцілей Пролог використовує два основні правила:

– пошук рішень підцілей здійснюється зліва на право;

– вибір предикатів для розгляду при рішенні кожної підцілі здійснюється в тому порядку, у якому вони з’являються в програмі.

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

Відкат (або повернення) автоматично ініціюється системою Прологу, якщо не використовуються спеціальні засоби керування ним.

Для керування процесом відкату в Пролозі передбачені два предикати: fail (невдача) і cut (відсікання).

2.4 Використання відкату після невдачі для організації найпростішого інтерфейсу виводу

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

Одним зі способів реалізації даної задачі є використання методу відкату після невдачі, що використовує предикат fail. Приклад використання цього предиката демонструє програма 2.3.

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

domains

name,firm=symbol

office=integer

object=labour; hobby(name); project(name,firm)

predicates

work(name, office)

colleague(name, name)

unite(name, name, object)

all_colleague(name, name, object)

query

do_answer(namе)

goal

query.

clauses

colleague(Man1,Man2):-work(Man1,X), work(Man2,X), Man1<>Man2.

all_colleague(X, Y, Z):- colleague(X,Y), Z=labour.

all_colleague(X, Y, Z) :- unite(X, Y, Z).

all_colleague(X, Y, Z) :- unite(Y, X, Z).

unite(„Возняк”, „Денега”, labour ).

unite(„Петренко”, „Скрипник”, project("New system",ics)).

unite(„Козлов”, „Петренко”, labour).

unite(„Савюк” , „Петренко”, hobby(sport)).

work(„Грищенко”, 101).

work(„Кардаш”, 111).

work(„Петренко”, 101).

work(„Скрипка”, 101).

work(Man1, N):-unite(Man1, Man2, labour), work(Man2, N).

query:- write(„Введіть прізвище –> ”), readln(Who), do_answer(Who).

do_answer(X):- colleague(X, Y), write(„ „, X, ”колега „, Y), nl, fail.

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

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

При виконанні запитів програма послідовно звертається до фактів і правил. При цьому правила часто вимагають, щоб задачі типу пошуку елементів у базі, вводу або виводу даних виконувалися багаторазово. Однак у Пролозі немає можливості безпосереднього завдання ітераційного процесу, тобто не реалізовані синтаксичні конструкції типу 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 або викликати пошук із поверненням, тобто забезпечувати відкат.

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]