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

Глава 13 Практические рекомендации

Описывая в предыдущих главах программы на чистом Прологе и его расширениях, почти все внимание мы уделяли разъяснению основополагающих понятий, Однако при практическом программировании следует заботиться об эффективности программ, учитывать ограничения, связанные с конкретной реализацией, используемой системой программирования и другими факторами. В фольклоре логического программирования имеется большое число приемов и трюков, необходимых для создания нетривиальных рабочих программ на Прологе. В этой главе наши интересы смещаются к более прагматичным задачам разработки программ на Прологе.

Технология программирования для логических языков имеет тот же смысл, что и для процедурных языков. Методология разработки и сопровождения больших программных комплексов для Пролога так же необходима, как и для любого Другого языка программирования. Не меньшую важность представляет хороший стиль программирования.

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

13.1. Эффективность программ на Прологе

В практическом программировании на Прологе следует обращать внимание на эффективность программ. Для обсуждения этого понятия нам следует установить критерии оценки программ. Основной оцениваемый параметр-число выполненных унификации и число попыток унификации в процессе вычисления. Этот параметр связан с временем работы программы. Еще один параметр-глубина вложенной рекурсии. Если в процессе вычислений глубина станет больше максимально допу­стимой, то вычисления прервутся. На практике эта проблема является основной. Третий параметр-число порожденных структур данных. Мы последовательно рассмотрим эти параметры.

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

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

Для указанных алгоритмов применимы обычные методы анализа сложности вычислений. Если не используется полная унификация (унификация двух произвольных термов цели), то можно показать, что время выполнения редукции цели с помощью предложения программы ограничено константой. Величина константы зависит от программы. Поэтому число выполняемых в программе редукций, как функция от размера ее входа, является хорошей оценкой временной сложности

программы.

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

Основной способ повышения эффективности программ - совершенствование алгоритма. Хотя речь идет о декларативном языке, понятие алгоритма в Прологе остается тем же, что и в других языках программирования. Примеры удачных и неудачных алгоритмов решения одной и той же задачи приведены в предыдущих главах вместе с записью этих алгоритмов на Прологе. Ясно, что линейное обращение списков с использованием накопителей (программа 3.16Ь) эффективнее непосредственного обращения (программа 3.16 а). Быстрая сортировка (програм­ма 3.22) лучше сортировки перестановкой (программа 3.20).

Помимо выбора наиболее удачного алгоритма можно использовать еще не­сколько способов для увеличения эффективности программ на Прологе. Один из них состоит в выборе наилучшей реализации. Эффективная реализация характеризуется исходной скоростью, возможностями индексирования, применением оптимизации остатка рекурсии и методом сборки мусора. Единицей измерения скорости выпол­нения программы на языке логического программирования обычно служит LIPS- число логических выводов в секунду. При вычислениях логический вывод соответствует редукции,

При фиксированной реализации сами программы могут быть улучшены за счет

• упорядочения целей в соответствии с правилом: чем раньше возникает отказ, тем лучше,

• устранения недетерминированности путем введения явных условий и отсечений,

• использования возможностей индексирования с помощью соответствующего упорядочения аргументов.

Проблема упорядочения целей рассматривалась в разд. 7.3. В разд. 11.1 обсуждалось, как использовать зеленые отсечения для выражения детерминизма программы.

Как было сказано в разд. 11.2, индексирование существенно при обработке конъюнктивных целей в процессе оптимизации остатка рекурсии. Даже в программах без остатка рекурсии индексирование может привести к увеличению эффективности, так как оно ограничивает поиск применимых правил. Это может иметь значение в программах, представляющих наборы фактов в виде таблиц. например в синтаксическом анализаторе и компиляторе.

В литературе, посвященной Прологу, не много внимания уделяется минимизации числа порождаемых структур данных. Рассмотрим эту проблему на примере. Предикат sublist (Xs, Ys), устанавливающий, является ли список Xs подсписком списка Ys, может иметь несколько определений. Сравним эффективность двух таких определений, отличающихся порождаемыми структурами данных. При этом ограничимся одним определенным использованием-проверкой, является ли один данный список подсписком другого данного списка.

Два рассматриваемых варианта определения предиката sublist используют программу 3.13 для вычисления суффикса и префикса списка. Предложение (i) определяет подсписок как префикс суффикса, а предложение (и)-как суффикс префикса:

sublist(Xs, AXBs) suffix(XBs, AXBs),prefix(Xs, XBs), (i)

sublist (Xs, AXBs) prefix(AXs, AXBs), suffix (Xs, AXs). (ii)

Хотя эти две программы логически эквивалентны, эффективность их различна. Если оба аргумента предиката sublist -полные списки, то предложение(i) означает просмотр второго списка от конца к началу с возвращением суффикса, а затем проверку, является ли первый список префиксом суффикса. Такое вычисление не порождает новых промежуточных структур данных. С другой стороны, выполнение предложения(ii) приводит к созданию нового списка, являющегося префиксом второго списка. Далее проверяется, является ли первый список суффиксом этого списка. Если проверка выполнилась неудачно, то происходит возврат и создается новый префикс первого списка.

Хотя число редукций в среднем в этих двух программах одинаково, эффективность их выполнения все же различна. Первая программа не создает новых структур данных (на жаргоне языка Лисп «не применяет cons»). Вторая программа создает новые структуры. При анализе программ на Лиспе обычно тщательно исследуется соns-характеристика программы, поскольку при оценке эффективности программы существенно, применяется ли в ней cons. Нам кажется, что этот вопрос столь же важен и для программ на Прологе. Однако искусство анализа больших программ на Прологе, вероятно, не достигло еще должной стадии.

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