Структуры управления
Условный оператор: пример
Усовершенствуем наш последний пример с циклом. Представьте, что мы хотим, чтобы на пересадочных станциях вместо красной точки отображалась бы желтая мигающая точка в течение более длительного времени. Класс TOURISM предусмотрительно заготовил для этих целей метод show_blinking_spot, который дополняет метод show_stop, используемый ранее.
Для достижения требуемого результата в нашей программе придется сделать следующее изменение:
from Line8.start invariant not_before_unless_empty: (not is_empty) implies (not is_before) — "Точка отображена для всех станций перед позицией курсора" until Line8.is_after loop if Line8.item.is_exchange then show_blinking_spot (Line8.item.location) else show_spot (Line8.item.location) end Line8.forth variant Line8.count - Line8.index + 1 endЛистинг 7.2.
В условном операторе трижды используется выражение Line8.item - вызов запроса. Более элегантно вычислять такой результат один раз, дав ему имя, а затем использовать это имя. Вскоре мы покажем, как это делать.
Время программирования!
Измените предыдущий пример - метод traverse в классе ROUTES - с учетом приведенного выше условного оператора. Запустите систему и получите результат.
Для записи условного оператора нам понадобятся четыре новых ключевых слова: if, then и else, а также elseif, которое появится чуть позже. Базисная структура оператора перед вами:
if condition then Compound_1 else Compound_2 end
Здесь condition (условие) — это булевское выражение, а Compound_1 и Compound_2 — составные операторы, последовательности из нуля или более операторов.
Структура условного оператора и ее вариации
Будучи последовательностями из нуля и более операторов, как Compound_1, так и Compound_2 могут быть пустыми операторами, поэтому можно писать (хотя такой стиль не рекомендуется):
if condition then Compound_1 else <--------- Здесь ничего end
В этом варианте else-часть, хотя и присутствует, но в ней ничего нет. Это соответствует частому случаю, когда нужно выполнить некоторые действия при выполнении определенного условия; в противном случае делать ничего не нужно. Вместо того чтобы писать else-часть без операторов, разрешается просто ее опускать. Можно писать (рекомендуемый стиль):
if condition then Compound_1 <--------- Без предложения else end
В любой форме — с присутствием else или без него — любые операторы, входящие в составной оператор, могут быть сами структурами управления, циклами или составными операторами.
Предположим, что некоторые станции метро могут быть связаны с железной дорогой, и для таких станций нужно выполнять особые действия. Предлагаемую схему можно использовать вместо предыдущего цикла.
Стиль этого примера не рекомендуется. Рекомендуемый стиль записи появится чуть позже.
from ... invariant ... until ... loop — Пропущенные предложения цикла смотри в листинге 2.2 if Line8 .item .is_exchange then show_blinking_spot (Line8 .item .location) else if Line8 .item .is railway connection then show_big_blue_spot ( Line8 .item .location) else show_spot ( Line8 .item .location) end end Line8 .forth variant ... endЛистинг 7.3.
Включение структур управления внутрь других структур называется гнездованием или вложенностью. Здесь условный оператор вложен в другой условный оператор, в свою очередь, вложенный в цикл.
Почувствуйте стиль
Теоретически ограничений на глубину вложенности нет. Ограничения диктуются практикой: хорошим вкусом и желанием сохранить читабельность программы, простоту ее понимания.
В последнем примере глубина вложенности равна четырем, и это максимум того, что следует допускать в повседневном программировании. Это не абсолютное правило: некоторые алгоритмы по-настоящему требуют более высокой вложенности. Но, всякий раз, когда вы достигаете такого уровня вложенности, следует остановиться и проанализировать, нельзя ли этого избежать. Альтернативой обычно является выделение части структуры как независимой подпрограммы, с заменой непосредственного вхождения ее вызовом. В следующей лекции о подпрограммах пойдет подробный разговор
В примерах, таких как пример 7.3, глубина вложенности делает структуру более сложной, чем это фактически необходимо. Ее можно упростить, не обращаясь к подпрограммам. Это упрощение применимо к условным операторам, вложенным в else-часть других условных операторов:
if condition_1 then ... else if condition_2 then ... else if condition_3 then ... else ... ...Последующие вложенные вхождения if ... then ... else ... end ... end end end
В такой структуре вложенность производит обманчивое впечатление сложности, в то время как фактическая структура решения — последовательная:
- если имеет место condition_l, выполните первую then-часть и ничего более;
- для i > 1, если имеет место condition_i но ни одно из предыдущих условий condition_j не выполнено для j < i, выполните i-ю then-часть и ничего более;
- если ни одно из условий condition_i не выполняется, то выполните наиболее вложенную else-часть и ничего более.
Ключевое слово elseif позволяет удалить излишнюю вложенность в этом случае, написав последовательные варианты на одном уровне:
if condition_1 then ... elseif condition_2 then ... elseif condition_3 then ... elseif ... Последующие условия при необходимости then ... else — Как ранее, else-часть является возможной ... end
Первый вариант структуры подобен матрешке:
Второй вариант гребенчатой структуры не столь хитроумен, но более понятен: Ключевое слово elseif, написанное как единое слово, не следует смешивать с парой подряд идущих слов else и if, использованных в варианте с матрешкой, поскольку в этом случае каждое if должно иметь свои собственные then и end.
Используя elseif, мы можем переписать пример 7.3 в виде одного условного оператора без применения вложенности:
from ... invariant ... until ... loop — Опущенные предложения цикла такие же, как в листинге 2.2 if Line8 .item .is_exchange then show_blinking_spot ( Line8 .item .location) elseif Line8 .item .is_railway_connection then show_spot ( Line8 .item .location) else show_spot ( Line8 .item .location) end Line8 .forth variant ... end
Условный оператор: синтаксис
Приведем сводку форм условного оператора.
Синтаксис
Кстати, если вы находите, что этот способ описания синтаксиса многословен и недостаточно точен, то вы правы. Лучший способ описания таких конструкций дает нотация, известная как нотация БНФ. Мы познакомимся с ней в лекции, посвященной синтаксису. Неформальные спецификации, сопровождаемые примерами, пока достаточны для понимания.
Условный оператор: семантика
Предыдущее обсуждение позволяет понять эффект действия условного оператора.
Семантика
Выполнение условного оператора состоит в выполнении не более одного составного оператора, входящего в одну из частей: "Then", "Else If", если присутствует, "Else", если присутствует. Какой оператор будет выполняться?
- Если условие, следующее за if, имеет значение True, то выполняется составной оператор части Then.
- Если это условие ложно и существуют Else_if, то первая из таких частей, для которой выполняется условие, и определяет выполняемый составной оператор.
- Если ни одно из рассмотренных выше условий не выполняется и существует Else-часть, то она определяет выполняемый составной оператор.
- Если ничего из выше рассмотренного не применимо, то никакой составной оператор не выполняется и действие условного оператора в этом случае эквивалентно пустому оператору.
Условный оператор: корректность
Корректность условного оператора определяется корректностью каждой его ветви в предположении, что выполняется условие для этой ветви.
Корректность
Чтобы условный оператор if c then a else b end был корректным, следует убедиться, что перед его выполнением:
- если c имеет место, то должно выполняться предусловие a;
- если c не выполняется, то должно выполняться предусловие b.
Из конъюнкций постусловий a and b - и условия, при котором каждое из них выполняется, - должно следовать желаемое постусловие для всего составного оператора.
Обобщите самостоятельно это правило на общую конструкцию, включающую предложения elseif.