Спецификация программ и преобразователь предикатов
Определение простейших операторов языка Java
До сих пор все наши манипуляции с основывались на том, что мы считали известным, как именно выполняются те или иные команды, из которых состоит программа .
Сейчас мы полностью изменим точку зрения. Будем считать первичным предикат и условия, которым он удовлетворяет. Это позволит нам определить в терминах все команды языка, а затем доказывать всевозможные утверждения о программах.
Первым оператором, который мы определим, будет пустой оператор.
Определение 6.6. .
Определение не требует доказательства, однако полезно убедиться, что оно не противоречит нашему внутреннему пониманию того, как именно работает пустой оператор. Проверьте это сами.
Определение 6.7. .
Выполнение вызова метода " System.exit(0) " приводит к немедленному завершению выполнения программы. Поэтому вполне естественно, что ни при каком начальном состоянии после его выполнения предикат истинным не будет.
Следующее определение связано с последовательным выполнением двух операторов одного за другим.
Определение 6.8. .
В случае последовательного выполнения нескольких операторов данным определением нужно воспользоваться многократно.
Более сложным и интересным является определение оператора присваивания, которое будет рассмотрено нами в двух вариантах. Сначала рассмотрим случай присваивания простой переменной.
Определение 6.9. , где — предикат, описывающий множество всех состояний, в которых может быть вычислено значение (т.е., где определено), а обозначает подстановку в предикат выражения вместо всех свободных вхождений переменной .
Это определение может вызвать определенные вопросы, так как на первый взгляд кажется, что оно не соответствует нашему интуитивному пониманию того, что делает оператор присваивания. Поэтому рассмотрим ряд примеров, которые развеют эти сомнения.
, что вполне правильно, так как присваивание переменной числа 5 всегда делает .
, что тоже правильно, ибо присваивание переменной числа 5 никогда не может сделать .
Часто можно позволить себе опустить предикат и считать, что , так как присваивание всегда должно выполняться только в тех ситуациях, когда может быть вычислено. В случае сомнений, однако, лучше воспользоваться исходным определением.
.
Случай присваивания элементу массива несколько сложнее, так как выражение само по себе может оказаться неопределенным из-за некорректного значения индекса . Введем предикат , который будет определять множество допустимых значений индекса.
Определение 6.10. Для присваивания элементу массива слабейшее предусловие .
В качестве примера рассмотрим массив и вычислим слабейшее предусловие
Оператор if и слабейшее предусловие
Перед тем, как дать формальное определение оператора if-else в терминах , заметим, что управляющая конструкция if (без else части) эквивалентна использованию пустого оператора в else -ветви. Оператор switch также может быть заменен несколькими вложенными друг в друга операторами if-else. Таким образом, для того чтобы задать все основные конструкции выбора языка Java, достаточно дать определение только одной из них, — конструкции "if (e) S1; else S2;".
Определение 6.11.
В качестве примера использования этого определения убедимся в том, что
В самом деле,
Покажем, что каждый из двух членов получившейся конъюнкции является тавтологией. Рассмотрим, например, первый из них — . Если , то истинен первый член дизъюнкции. В противном случае и поэтому истинен ее второй член, что и доказывает требуемое. Аналогичные рассуждения можно провести и для выражения , что и завершает доказательство.
Для практических приложений часто необходимо не вычисление слабейшего предусловия, а лишь проверка того факта, что некоторое другое известное предусловие обеспечивает его выполнение. По этой причине полезна следующая теорема.
Теорема 6.1.
Пусть предикат удовлетворяет условию
Тогда (и только тогда)
Доказательство
Аналогично получаем
и, следовательно,
Циклы в терминах wp
В терминах слабейшего предусловия можно определить все оставшиеся еще неопределенными конструкции языка, но мы ограничимся только определением цикла while. Дело в том, что уже даже это определение оказывается достаточно бесполезным с точки зрения практики. Именно оно, однако, позволяет предложить несколько вполне конструктивных подходов к построению цикла, которые будут изучаться в следующей главе.
Для определения слабейшего предусловия нам потребуются следующие вспомогательные определения:
Определение 6.12. , , где предикат описывает множество всех состояний, в которых выполнение цикла "while(e)S;" заканчивается не более, чем за итераций, в состоянии, удовлетворяющем .
Теперь можно дать основное определение.
Определение 6.13. .
Для цикла "while (i<1) i=i+1;" и постусловия имеем . Действительно, именно при таком предусловии выполнение цикла завершится за ноль итераций и даст результат .
Далее, легко посчитать и .
Аналогично находим и т.д.