Некоторые правила хорошего стиля
Основные правила хорошего стиля программ на языке 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) .