Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛАБОРАТОРНАЯ РАБОТА 7.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
150.02 Кб
Скачать

Листинг 13.5. Программа ch06e05.Pro

% В 32-битной архитектуре эти примеры будут выполняться достаточно долго, занимая % много памяти и значительно уменьшая общую производительность системы.

predicates

badcount1(long)

badcount2(long)

badcount3(long)

check(long)

clauses

% badcount1: Рекурсивный вызов - не последний шаг.

badcount1(X):-

write ('\r',X),

NewX = X+l,

badcount1(NewX),

nl.

% badcount2: Это предложение, которое не выполняется во время

% осуществления рекурсивного вызова

badcount2(X):-

write ('\r',X),

NewX = X+l,

badcount2(NewX).

badcount2(X):- X < 0,

write("X отрицательно.") .

% badcount3: Непроверенная альтернатива в процедуре,

% вызванной перед рекурсивным вызовом.

badcount3(X):-

write ('\r',X),

NewX = X+l,

check(NewX),

badcount3(NewX).

check(Z):- Z >= 0.

check(Z):- Z < 0.

Заметьте, что badcount2 и badcount3 хуже, чем badcount1, потому что они генериру­ют точки возврата.

Вероятно, вы сейчас думаете, что невозможно гарантировать, что процедура являет­ся оптимизированной хвостовой рекурсией. Хотя довольно просто сделать рекурсив­ный вызов в последней подцели заключительного предложения, но как гарантиро­вать, что в любых других вызываемых предикатах нет альтернатив?

Отсечение позволяет отвергать все возможные излишние альтернативы. Чтобы уста­новить cut, необходимо использовать директиву компилятора check_determ.

Вы можете исправить badcount3 следующим образом (модифицируя его имя):

cutcount3(X) :-

write ('\r',X),

NewX = X+l,

check(NewX),

!,

cutcount3(NewX).

Команда "отсечение" означает "сжечь мосты за собой", или, точнее, "однажды дос­тигнув этой точки, не обращать внимания на альтернативные предложения этого предиката и альтернативные решения предыдущих подцелей в данном предложе­нии". Что точнее – решайте сами. Поскольку альтернативы исключаются, фрейм стека не нужен и рекурсивный вызов может свободно идти дальше.

"Отсечение" также эффективно и в badcount2, если переместить проверку из второго предложения в первое:

cutcount2(X) :-

X >= 0,

!,

write('\r',X),

NewX = Х+1,

cutcount2(NewX).

cutcount2(X) :-

write("X is negative.").

Отсечение – это действительно решение. Оно используется всякий раз, когда аль­тернативы нам не интересны. В исходной версии предыдущего примера второе предложение должно было оставлять выбор, т. к. первое предложение не содержало проверки Х. Переместив проверку в первое предложение и отрицая ее, решение можно принять уже там, а отсечение установить в соответствии с утверждением: "Теперь я знаю, что я не должен писать, что Х отрицателен".

То же касается cutcount3. Предикат check показывает ситуацию, когда вы хотите совершить некую дополнительную операцию над Х, основанную на знаке. Однако код для check недетерминирован, и отсечение после его вызова – это все, на что вам надо решиться. Однако вышесказанное немного искусственно – возможно, бы­ло бы правильнее, чтобы check был детерминирован:

check(Z) :-Z >= 0,

!,

... % использование Z

check(Z) :-Z < 0,

... % использование Z

Проверка во втором предложении check – полное отрицание проверки в первом, поэтому check можно переписать как:

check(Z) :-

Z >= 0,

!,

%. . .

Если отсечение выполняется, компьютер предполагает, что непроверенных альтер­натив нет, и не создает стековый фрейм. Программа ch06e06.pro (листинг 13.6) содержит измененные версии badcount2 и badcount3.