Некоторые правила хорошего стиля

Основные правила хорошего стиля программ на языке Prolog приведены ниже.

• Предложения программы должны быть короткими. Тело предложения, как
правило, должно содержать лишь несколько целей.

• Процедуры должны быть небольшими, поскольку длинные процедуры являют­ся сложными для понимания. Но допускается применение длинных процедур, если они имеют некоторую единообразную структуру (эта тема рассматривает­ся более подробно ниже в данном разделе).

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

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

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

• Оператор отсечения должен использоваться с осторожностью. Эти операторы
не следует применять в тех случаях, если без них можно легко обойтись. По
возможности, лучше использовать зеленые операторы отсечения, а не красные
операторы отсечения. Как было описано в главе 5, оператор отсечения назы­
вается зеленым, если после его удаления декларативное значения предложе­
ния не изменяется. Использование красных операторов отсечения должно
быть ограничено такими четко определенными конструкциями, как not или
выбор между несколькими взаимоисключающими вариантами. Ниже приведен
пример конструкции последнего типа.

если Condition, то Goall, иначе Goal2

Ее можно перевести на язык Prolog с помощью операторов отсечения следую­щим образом:

Condition, !, % Условие Condition является истинным?

Goall * Если да, то Goall,

Goal2 % иначе Goal2

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

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



Часть I. Язык Prolog

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

• В результате использования точки с запятой смысл предложения может стать
менее очевидным; иногда удобство программ для чтения может быть повыше­
но путем разделения предложения, содержащего точку с запятой, на несколь­
ко предложений. Но возможно также, что это улучшение будет достигнуто за
счет увеличения длины программы и снижения ее эффективности.

В качестве иллюстрации к нескольким рекомендациям, изложенным в данном разделе, рассмотрим следующее отношение: merge ( Listl, List2, List3)

где Listl и List2 — упорядоченные списки, которые сливаются в список List3, например: merge< [2,4,7], [1,3,4,8],[1,2,3,4,4,7,8] )

Ниже приведен пример реализации процедуры merge, выполненный в плохом стиле. merge; Listl, List2, List3) :-

Listl " [],!, List3 = List2; % Первый список пуст

List2 - [],!, List3 = Listl; % Второй список пуст Listl = [X | Restl],

List2 = [Y 1 Rest2),

[ X < Y, ! ,

Z = X, % Z - голова списка List3 merge ( Restl,List2, Rest3) ; Z = Y,

merge; Listl, Rest2, a*st3)L List3 = [Z | Rest3].

А ниже представлена улучшенная версия этой процедуры, в которой исключены точки с запятой. rae^ge|[|, List, List) :-

!. % исключав* выработку лииних решений

merge! List, [], List). merge! [X j Restl], [Y | Rest2], [X I RestSl) :-

X < Y, !, merge ( Restl, [Y [ Rest2], Rest3). merge! Listl, [Y | Rest2], [Y | Rest3]) :-

merge! Listl, Rest2, Rest3) .

Наши рекомендации