Декларативная и процедурная трактовка программы

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

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

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

Прогресс в технологии программирования достигается за счет все более глубокого ухода к декларативным аспектам (они легче понимаются и легче поддаются формальному описанию). Желательно все процедурные детали переложить на саму систему.

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

Пример. Вернемся к задаче о родственных отношениях. Предположим, что мы определили отношение – предок так (см рис.2.5. 2)):

Рис.2.5. Влияние переупорядочения предложений в программе с использованием рекурсии

На рис 2) с декларативной точки зрения все в порядке.

Но при процедурной трактовке смысл становится совершенно другим. Переменная Z здесь не конкретизируется в момент обработки рекурсивной подцели ancestor(X,Y). У нас первым стояло предложение parent(Y,Z). Оно вырабатывало новое значение переменной Y, а уже потом использовало это новое значение в рекурсивной подцели ancestor(X,Y). Теперь этого нет. К чему это приведет? Это приведет к тому, что когда компилятор будет пытаться выполнить запрос к процедуре ancestor, то вначале он отыщет правильные ответы, а затем будет выполнять рекурсивные действия вплоть до исчерпания доступного объема памяти. Это происходит потому, что рекурсивный вызов не является последним в предложении, а стоит раньше других подцелей. Cтратегия же решения задачи в компиляторе – другая, поэтому не будет надежной обработки.

Попробуйте самостоятельно сформулировать правило, отображенное на рис 1). А теперь попытайтесь объяснить, что произойдет с программой, в которой процедура ancestor представлена так как на рис 3).

Когда мы пишем программу, то используем процедурное понимание. Когда мы определяем значение программы, рассматривая это значение с точки зрения истинности, то применяем декларативное понимание.

В “чистом прологе” декларативное значение программ не зависит от порядка предложений и порядка целей в предложениях.

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

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


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: