Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Основы программирования на языке Turbo Prolog.doc
Скачиваний:
56
Добавлен:
09.11.2019
Размер:
563.2 Кб
Скачать

2. Отсечение (!)

Автоматический перебор возможных вариантов — полезный программный механизм, так как он освобождает от необходимости программировать его самому.

С другой стороны, ничем не ограниченный перебор может стать источником неэффективности программы.

Поэтому необходимо уметь его ограничить или исключить вовсе.

Для этих целей Турбо-Пролог имеет встроенный предикат cut (отсечение). Предикат cut обозначается символом восклицательного знака (!). Этот предикат, вычисление которого всегда завершается успешно, заставляет внутренние унификационные подпрограммы «забыть» все указатели возврата, установленные во время попыток вычислить текущую подцель. Другими словами, предикат cut устанавливает «барьер», запрещающий выполнить возврат ко всем альтернативным решениям текущей подцели.

Более точно, отсечение имеет два побочных (т.е. проявляемых при возврате) эффекта:

1. БЛОКИРУЕТ ВОЗВРАТ К ПРЕДШЕСТВУЮЩИМ ЕМУ ПОДЦЕЛЯМ В ДАННОМ УТВЕРЖДЕНИИ.

правило1:-

согласована подцель1, передоказать

согласована подцель2, нельзя

!,

согласована подцель3, попытка передоказать

отказ подцель4.

2. ЗАПРЕЩАЕТ ИСПОЛЬЗОВАНИЕ ВСЕХ УТВЕРЖДЕНИЙ ДАННОЙ ПРОЦЕДУРЫ, КОТОРЫЕ В БАЗЕ ДАННЫХ НАХОДЯТСЯ ПОСЛЕ ДАННОГО.

правило1:- передоказать

согласована подцель1, нельзя

!,

отказ подцель2.

правило1:- передоказать

<.......>.

правило1:- нельзя

< .......>.

Действие отсечения превращает процедуру, способную генерировать альтернативные варианты означивания переменных цели (такая процедура называется НЕДЕТЕРМИНИРОВАННОЙ), в процедуру, порождающую лишь один ответ (ДЕТЕРМИНИРОВАННУЮ).

3. Программирование альтернатив

Рассмотрим кусочно-гладкую функцию (пример 4.2).

Пример 4.2.

f(x)=0, если x<3.

f(x)=1, если 3<=x<=5.

f(x)=0, если x<5.

Функция определяется тремя взаимоисключающими правилами.

Воспользуемся декларативным принципом Пролога —

КАЖДОЙ АЛЬТЕРНАТИВЕ — СВОЕ УТВЕРЖДЕНИЕ:

f(X,0):- X<3.

f(X,1):- X>=3, X<=5.

f(X,2):- X>5.

При запросе

goal

f(1,Y), Y>2.

первое правило даст отказ, затем будут проверены второе и третье, затем система ответит «нет».

Очевидно, что если выполнилась одна из трех альтернатив, нет смысла проверять остальные. Укажем системе, что возврат не нужен:

f(X,0):- X<3,!.

f(X,1):- X<=5,!.

f(X,2):- X>5.

Если сейчас мы ПОМЕНЯЕМ МЕСТАМИ УТВЕРЖДЕНИЯ, ТО МОЖЕТ ИЗМЕНИТЬСЯ ТОЛЬКО ЭФФЕКТИВНОСТЬ ПРОГРАММЫ, НО НЕ ЕЕ ПРАВИЛЬНОСТЬ.

Отсечения, которые меняют процедурное поведение программы, но не ее декларативный смысл, называются ЗЕЛЕНЫМИ.

Заметим, что третья альтернатива не нуждается в проверке, так как получается автоматически при отказе первых двух:

f(X,0):- X<3,!.

f(X,1):- X<=5,!.

f(X,2).

Теперь ПРИ ПЕРЕСТАНОВКЕ УТВЕРЖДЕНИЙ ПРОГРАММА БУДЕТ ДАВАТЬ НЕВЕРНЫЕ РЕЗУЛЬТАТЫ.

Отсечения, которые меняют декларативный смысл программы, называются КРАСНЫМИ.

Далеко не всегда возникает необходимость в использовании «красных» отсечений. Запрограммируем функцию, выбирающую максимум из двух чисел (пример 4.3)

Пример 4.3.

max(real,real,real).

max(X,Y,Y):-

Y>=X,!. % «зеленое отсечение»

max(X,Y,X):-

Y<X.

Перепишем ее с использованием «красного» отсечения:

max(X,Y,Y):-

Y>=X,!. % ”красное отсечение”

max(X,Y,X).

При запросах типа max(3,7,M) процедура будет вести себя правильно, но на запрос max(3,7,3) (максимум из 3 и 7 равен 3 ?) система ответит «да»...

Исправим процедуру:

max(X,Y,M):-

Y>=X,!,M=Y.

max(X,Y,X):-

Y<X.

Но лучшим решением все же был первый вариант с использованием «зеленого» отсечения.

Рассмотрим «геометрический» пример на использование альтернатив (пример 4.4)

Пример 4.4.

На плоскости задан круг радиуса R, вписанный в квадрат с центром в начале координат. Сколько точек, брошенных на плоскость, попадут:

— вне квадрата;

— внутрь круга;

— вне круга, но внутри квадрата.

Составим вначале программу, которая будет показывать местонахождение одной точки.

/* Программа 4.2 «Точка». Назначение: */

/* демонстрация использования отрицания */

/* при программировании альтернатив. */

predicates

show_point % показать точку

%вычисление места точки

pos_point(real,real,real)

out_sqr(real,real,real) % вне квадрата

in_circ(real,real,real) % внутри круга

goal

show_point.

clauses

show_point:-

write(" R? "), readreal(R),

write(" X? "), readreal(X),

write(" Y? "), readreal(Y),

pos_point(X,Y,R).

pos_point(X,Y,R):-

out_sqr(X,Y,R),

write(" вне квадрата"), nl.

pos_point(X,Y,R):-

in_circ(X,Y,R),

write("внутри круга"), nl.

pos_point(X,Y,R):-

not(out_sqr(X,Y,R)),

not(in_circ(X,Y,R)),

write("вне круга,внутри квадрата"),nl.

out_sqr(X,Y,R):- % точка вне квадрата

abs(X)>R;

abs(Y)>R.

in_circ(X,Y,R):- % точка внутри круга

X*X+Y*Y<R*R.

/* Конец программы */

Упражнение 4.2.

Модифицировать программу 4.2, использовав отсечение ! вместо отрицания not при программировании альтернатив.

Теперь будем запрашивать точки в цикле.

Испробуем наш испытанный метод — возврат после неудачи:

show_point:-

write(" R? "), readreal(R),

write(" X? "), readreal(X),

write(" Y? "), readreal(Y),

pos_point(X,Y,R),

fail.

Увы, предикат read согласуется ровно один раз и никогда не передоказывается при возвратах. Поэтому после первой же прочитанной точки мы выйдем из программы.