Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
AlgStr / Библиотека / ЛЕКЦИИ / POSIBNIK / ПРОГР НА ПРОЛОГЕ.doc
Скачиваний:
42
Добавлен:
23.03.2015
Размер:
669.7 Кб
Скачать

5.7. Предикат відсікання

Предикат відсікання (“!” або cut) – процедурний засіб, що розмиває декларативну інтерпретацію програм, але підвищує ефективність виконання програми за рахунок скорочення пошуку. Він обмежує число альтернатив, досліджуваних ПРОЛОГом при відкотах. При виклику як ціль він завжди успішно узгоджується і не може бути узгоджений повторно при відкотах. Має два побічних ефекти:

  1. блокує повернення до попередньої підцілі в даному твердженні (прикл.1, рис. 16);

2) запобігає використанню всіх наступних тверджень у даній процедурі, які могли б бути використані для узгодження цілі, що відповідає даній процедурі (прикл. 2, рис. 17, 18).

Приклад 1

процес-1 :-

підціль 1, -- ціль узгоджується

підціль 2, -- ціль узгоджується

!,

підціль 3, -- ціль узгоджується

підціль 4. -- ціль дає відмову.

Якщо повторна спроба узгодження цілі “підціль 3” дає відмову, то відбувається повернення до відсікання і цілі “підціль 1” й “підціль 2” негайно дають відмову, бо їх альтернативні гілки блокуються (перший побічний ефект відсікання) (рис. 16).

процес-1

підціль-1 підціль-2 ! підціль-3 підціль-4

X

відмова

успіх успіх Ці гілки відсікаються

Рис. 16. Відсікання запобігає поверненню до більш ранніх підцілей у твердженні

Приклад 2

процес-2 :-

підціль-1, -- ціль узгоджується

!,

підціль-2. -- ціль дає відмову

процес-2:-

підціль-3

!,

підціль-4.

процес-2:-

підціль-5.

процес-2

підціль-1 ! підціль-2 підціль-3 ! підціль-4 підціль-5

успіх X

відмова

Ці гілки відсікаються

Рис. 17. Відсікання блокує використання тверджень у процедурі.

Відсікання в першому твердженні блокує повернення до другого і третього тверджень. Виклик предиката процес-2 відразу дає відмову, якщо дає відмову підціль-2 (рис. 17). Слід визначити відмінність даної ситуації від ситуації, зображеної у наступному прикладі, що відповідає відмові підцілі-1 (рис. 18).

Приклад 3

процес-2 :-

підціль-1, -- ціль дає відмову

!,

підціль-2.

процес-2:-

підціль-3 -- ціль узгоджується

!,

підціль-4. – ціль дає відмову

процес-2:-

підціль-5.

процес-2

підціль-1 ! підціль-2 підціль-3 ! підціль-4 підціль-5

X

відмова Блокується тільки ця гілка

Рис. 18. Відсікання у першому твердженні не досягнуто – можна застосовувати друге твердження.

Наведені міркування обумовлюють застосування відсікання з такою метою:

  • запобігання марних спроб пошуку при відкотах, коли програміст знає, що ціль не може бути узгоджена в принципі;

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

Перша мета застосування відсікання може бути продемонстрованя на такому прикладі:

Приклад 4

процедура( Арг_1, Арг_2, ..., Арг_n ):-

створити_об'єкт (Об'єкт),

створити_множину (Множина),

належить(Об'єкт, Множина),

перевірити (Арг_1, Об'єкт),

обробити (Арг_1, Множина, Рез_1),

…,

перевірити (Арг_n, Об'єкт),

обробити(Арг_n, Множина, Рез_n).

Якщо “Об'єкт” належить списку “Множина”, а виклик предиката “перевірити” дає відмову, то ПРОЛОГ повернеться до перевірки на приналежність об'єкта множині і буде шукати його повторні входження в залишок списку. Через те що множина не може містити дублюючих елементів, зрозуміло, що цей пошук буде марним. Така поведінка процедури обумовлюється її недетермінованою реалізацією:

належить(H,[H | _]). % недетермінована реалізація

належить(H,[_ | T]):- % процедури “належить”

належить(H,T).

Це можна усунути, перевизначивши предикат “належить” у такий спосіб:

належить(H,[H|_]) :- !. % детермінована реалізація

належить(H,[_|T]):- % процедури “належить”

належить(H,T).

При відкоті ПРОЛОГ відразу ж повернеться до підцілі “створити_множину” і не буде шукати повторних входжень. Відсікання, застосоване зазначеним способом, дозволяє не змінювати створювані програмою результати. При цьому його можна розглядати як механізм скорочення перебору в чистому вигляді. Крім часу, відсікання заощаджує і пам'ять, тому що зменшується кількість пунктів, у які ПРОЛОГ потенційно може повернутися й кожний із яких повинен бути запам’ятований. Але, хоча відсікання може не змінювати поведінку всієї програми, включення його в процедуру завжди змінює поведінку цієї процедури.

Уведення відсікання в предикат “належить” перетворює процедуру з недетермінованої у детерміновану. Розміщення відсікання завжди змінює аспекти поведінки процедури. Тепер уже не можна застосовувати цей предикат для генерації елементів списку:

Ціль: належить(Об'єкт, [червоний, зелений, блакитний] ).

Відповідь:

Об'єкт = червоний

Один розв’язок

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

Висновок: Відсікання перетворює процедуру з недетермінованої (дає альтернативні значення змінним цілі) на детерміновану (викликає лише одну відповідь).

Куди слід поміщати відсікання?

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

Розглянемо такі випадки:

1) стан ідентифікується зразком у заголовку твердження – відсікання ставиться першою підціллю тіла.

2) стан ідентифікується деякою підціллю тіла – відсікання міститься безпосередньо за цієї підціллю.

Альтернативи не відсікаються доти, поки відсікання не буде досягнуто. Але як тільки стан буде розпізнано (а значить і відсікання буде пройдене), то інші стани стануть недосяжними.

Використання відсікання:

1) підвищує ефективність програми;

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

Використання відсікання має і недоліки:

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

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

Наприклад, розглянемо визначення предиката

максимум(N1, N2, N2):-

N2>=N1.

максимум(N1, N2, N1):-

N2<N1.

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

Спробуємо застосувати відсікання:

максимум(N1, N2, N2):-

N2>=N1, !.

максимум(N1, N2, N1).

Але ця процедура дасть помилку при узгодженні наступної цілі:

Ціль: максимум(3, 7, 3)

Відповідь: так

Тобто процедура погодиться, що максимум із чисел 3 і 7 є 3. Це станеться тому, що відсікання в першому твердженні не буде досягнуто, оскільки виклик не узгодиться зі зразком у заголовку цього твердження, але при цьому виклик усе-таки завершиться успішно, через те що він узгодиться з іншим твердженням. Цю помилку можна усунути в такий спосіб:

максимум(N1, N2, N3):-

N2>=N1, !,

N3=N2.

максимум(N1, N2, N1).

Даний приклад демонструє той факт, що іноді слід застосовувати явний предикат “=” замість неявного узгодження. Але кращим розв’язком у даному випадку буде все-таки повна відмова від застосування відсікання.