Скачиваний:
52
Добавлен:
01.05.2014
Размер:
346.11 Кб
Скачать

12.5. Циклы, управляемые отказом

Интерактивные программы, описанные в предыдущем разделе, были основаны на неминимальных рекурсивных циклах. Существует другой способ записи циклов в Прологе, аналогичный записи циклов repeal в обычных языках программирования, Выполнение таких циклов управляется с помощью отказов, поэтому их называют циклами, управляемыми отказами. Такие циклы бывают полезны лишь при сов­местном использовании с внелогическими предикатами, имеющими побочный эффект. Работа таких циклов может быть понята только с операционной точки зрения.

Простым примером цикла, управляемого отказом, служит вопрос Goal, write (Goal), nl, fail?, который приводит к выводу всех решений цели goal на экран. Такой цикл использован в оболочках, описанных в программах 12.6 и 12,7.

Цикл, управляемый отказом, может быть использован при определении системного предиката tab(N), предназначенного для вывода на экран N пробелов. В нем используется отношение between, описанное в программе 8.5:

tab (N) between (1,N,I), put(32), fail.

Каждая интерактивная программа предыдущего раздела может быть переписана с использованием циклов, управляемых отказом. Новый вариант основного интерактивного цикла приведен в программе 12.8. Он основан на незавершающемся системном предикате repeat, который может быть задан с помощью минимальной рекурсивной процедуры, приведенной в программе 12.8. В отличие от программы 12.4 в данной программе решение цели echo(X) приводит к безуспешному вычислению, если только Х не символ конца файла. Безуспешное вычисление вызывает возврат к цели repeat, цель выполняется, считывается и затем выводится на экран следующий терм. Отсечение в определении предиката echo гарантирует от позднейшего повторения цикла repeat.

echo repeat, read(X), echo(X),!.

echo(X) end_of_file(Х),!.

echo(X) write(X), nl, fail.

repeat.

repeat repeat.

Программа 12.8. Основной интерактивный цикл repeat.

Цикл, управляемый отказом и использующий предикат repeat, имеет название repeat-цикл.Такие циклы аналогичны циклам вида repeat в обычных языках программирования. Repeat-циклы применяются в Прологе для описания интерактивного взаимодействия с внешней системой путем повторяющегося ввода и (или) вывода. В repeat-цикле обязательно должен присутствовать предикат, гарантированно приводящий к безуспешным вычислениям (в программе 12.8 это-цель echo(Х)), определяющим продолжение итерации. Такой предикат вычисляется успешно лишь в момент выхода из цикла. Можно сформулировать полезное эвристическое правило построения repeat- циклов: в теле правила, содержащего цель repeat, должно быть отсечение, предохраняющее от незавершающихся вычислений при возврате в цикл.

Мы используем repeat-цикл для определения системного предиката consult(File), предназначенного для чтения и последующего добавления к программе предложений из некоторого файла. Определение приведено в программе 12.9. Системные предикаты see(File) и seen используются соответственно для открытия и закрытия входного файла.

consult(File) see(File), consult_loop, seen

consult coop 

repeat, read(Clause), process(Clause),!.

process (X) 

end_of_file(X),!. process(Clause) 

assert (Clause), fail,

Программа 12.9. Обращение к файлу.

Рекурсивные циклы предпочтительнее repeat-циклов, поскольку последние не имеют логической интерпретации. На практике, однако, repeat-циклы часто необходимы при выполнении большого объема вычислений, особенно в реализациях Пролога без оптимизации остатка рекурсии и (или) без сборки мусора. Обычно явный отказ приводит к требованию некоторого зависящего от реализации объема памяти.

Упражнение к разд. 12.5

1. Определите предикат abolish (F, N), удаляющий все предложения для процедуры F арности N.

Соседние файлы в папке 1-13