
- •2.6. Заключение .............................................................................................................. 22
- •4. Язык исчисления вычислимых предикатов,
- •4.12. Однозначность предикатов .......................................................................................... 45
- •5. Семантика языка предикатного программирования.
- •6.9. Формулы .......................................................................................................................... 78
- •6.9. Процессы ......................................................................................................................... 79
- •6.11. Императивное расширение .......................................................................................... 82
- •7.8. Заключение ................................................................................................................... 108
- •Введение в курс предикатного программирования
- •1. Общее понятие программы
- •1.1. Автоматическая вычислимость
- •1.2. Спецификация программы
- •1.3. Формы спецификации программы
- •Список литературы
- •2. Корректность программ с предикатной спецификацией
- •2.1. Предикатная спецификация программы
- •2.2. Логическая семантика языка программирования
- •2.3. Модель корректности программы
- •2.4. Система правил доказательства корректности операторов
- •2.4.1. Правила для корректного оператора
- •2.4.2. Правила корректности для параллельного оператора
- •2.4.3. Правила корректности для оператора суперпозиции
- •2.4.4. Правила корректности для условного оператора
- •2.5. Система правил вывода программы из спецификации
- •2.5.1. Однозначность предикатов
- •2.5.2. Теорема тождества спецификации и программы
- •2.5.3. Правила корректности для параллельного оператора
- •2.5.4. Правила корректности для оператора суперпозиции
- •2.5.5. Правила корректности для условного оператора
- •2.6. Заключение
- •Список литературы
- •3. Математические основы
- •3.1. Отношения порядка
- •3.2. Наименьшая неподвижная точка
- •3.3. Математическая индукция
- •Список литературы
- •4. Язык исчисления вычислимых предикатов, его логическая и операционная семантика
- •4.1. Структура программы на языке ccp
- •4.2. Система типов данных
- •4.3. Логическая и операционная семантика языка ccp
- •4.4. Семантика вызова предиката
- •4.5. Оператор суперпозиции
- •4.6. Параллельный оператор
- •4.7. Условный оператор
- •4.8. Конструктор предиката
- •4.9. Конструктор массива
- •4.10. Программа
- •4.11. Рекурсивные определения предикатов
- •4.12. Однозначность предикатов
- •Список литературы
- •5. Семантика языка предикатного программирования. Методы доказательства корректности предикатных программ
- •5.1. Язык p1: подстановка определения предиката на место вызова
- •5.2. Язык p2: оператор суперпозиции и параллельный оператор общего вида
- •5.3. Язык p2: другое обобщение оператора суперпозиции
- •5.4. Язык p3: выражения
- •5.5. Методы доказательства корректности рекурсивных программ
- •6. Язык предикатного программирования
- •6.1. Введение
- •6.2. Лексемы
- •6.3. Предикаты
- •6.3.1. Определение предиката
- •6.3.2. Спецификация предиката
- •6.3.3. Вызов предиката
- •6.4. Программа
- •6.5. Операторы
- •6.6. Выражения
- •6.7. Типы
- •6.8. Массивы
- •6.8.1. Описание типа массива
- •6.8.2. Вырезка массива
- •6.8.3. Определение массива
- •6.8.4. Объединение массивов
- •6.9. Формулы
- •6.10. Процессы
- •6.11. Императивное расширение
- •Список литературы
- •7. Технология предикатного программирования
- •7.1. Подстановка определения предиката на место вызова
- •7.2. Замена хвостовой рекурсии циклом
- •7.3. Склеивание переменных
- •7.4. Метод обобщения исходной задачи
- •7.5. Трансформация кодирования структурных объектов
- •7.6. Пример. Сортировка простыми вставками
- •7.7. Гиперфункции
- •7.8. Заключение
- •Список литература
2.1. Предикатная спецификация программы
Уточним и дополним понятие предикатной спецификации, определенное в разд. 1.2. Рассмотрим следующую простую схему взаимодействия программы с окружением: ввод входных данных происходит перед началом исполнения программы, вывод результатов по завершению исполнения, а других взаимодействий с окружением нет. В данной схеме программа реализует функцию, отображающую значения входных данных в значения результатов. Допустим, программа представлена оператором S; x обозначает набор входных данных, а y набор результатов. Спецификация программы определяется формулой P(x) & Q(x, y), где P(x) предусловие, истинное перед исполнением программы, а Q(x, y) постусловие, истинное после исполнения программы. Программа со спецификацией представляется известной тройкой Хоара {P(x)} S {Q(x, y)}, см. [9].
Спецификация P(x) & Q(x, y) является предикатной при условии, что взаимодействие программы с окружением ограничивается вводом данных перед началом исполнения и выводом результатов после завершения. Программа принадлежит классу программ с предикатной спецификацией, если удается переместить ввод всех данных перед началом исполнения программы, а вывод после завершения исполнения. Для программы реального времени (реактивной системы) подобный перенос ввода и вывода принципиально невозможен. Такая программа относится к классу программ с процессной спецификацией [4; 5], поскольку эффект исполнения программы нельзя представить в виде функции эффект определяется только в виде процесса. Спецификация может быть адекватно представлена на языке алгебры процессов Р. Милнера [12] или Т. Хоара [13].
2.2. Логическая семантика языка программирования
Всякая программа содержит логику. Это, например, бизнес-логика, извлекаемая нетривиальным анализом из текста программы в процессе реинжиниринга программы [16]. Это также логические формулы, получаемые по программе в соответствии с формальной семантикой языка программирования (денотационной [8] или аксиоматической [9; 10]) в целях формального доказательства свойств программы.
Проанализируем происхождение логики программы. На рис. 2 представлена общая схема, отражающая связи задачи и программы. Программа является реализацией алгоритма решения некоторой математической задачи. Алгоритм строится с использованием свойств (утверждений, лемм, теорем), доказуемых из условия задачи. Описание алгоритма обычно является содержательным. Программа является результатом кодирования алгоритма на языке программирования.
Рис. 2. Связи между задачей и программой
Логика алгоритма включает свойства, использованные для построения алгоритма. Логика программы является трансформацией логики алгоритма вследствие кодирования алгоритма в конструкциях и структурах данных языка программирования. Оптимизации, совершаемые в процессе кодирования алгоритма в императивной программе, обычно приводят к трансформации логики, усложняя (искривляя) ее.
Формальная семантика языка программирования признана элегантным и мощным формализмом, однако не для реально используемого императивного языка программирования. Для него денотационная семантика оказывается сложной и громоздкой из-за сложности самого языка, а аксиоматическая семантика может быть построена лишь для некоторого простого подмножества языка. Эта оценка, данная Джоном Бэкусом 30 лет назад в своей тьюринговской лекции [17], остается справедливой в настоящее время для современных императивных языков. Таким образом, императивные языки это языки сложной и кривой логики, которую весьма трудно извлечь из программы.
Логическая семантика является простейшим способом определения логики программы. Логическая семантика есть функция LS, сопоставляющая каждой исполняемой конструкции S соответствующую формулу LS на языке исчисления предикатов, т. е. LS(S) = LS.
Определение логической семантики покажем на примере трех операторов языка исчисления вычислимых предикатов CCP 4 [3]. Подробное описание языка CCP будет дано в следующем разделе. Язык CCP определен как минимальное ядро, из которого можно породить любой чистый язык функционального программирования применением иерархической системы обозначений, свойственных языку. Таким способом определен язык предикатного программирования [7]; его описание будет дано в гл. 6.
Пусть A и B обозначают операторы, x, y и z различные непересекающиеся наборы переменных. Обозначение A: x y определяет оператор A с набором аргументов x и набором результатов y.
Оператор суперпозиции A; B определяет последовательное исполнение операторов A: x z и B: z y. Логическая семантика оператора суперпозиции определяется следующим образом:
LS(A; B)(x, y) $z ( LS(A)(x, z) & LS(B)(z, y) ) . (2.1)
Параллельный оператор A || B определяет параллельное исполнение операторов A: x y и B: x z. Логическая семантика определяется формулой:
LS(A || B) (x, y, z) LS(A)(x, y) & LS(B)(x, z) . (2.2)
Условный оператор if (C) A else B определяет исполнение одного из операторов A: x y и B: x y в зависимости от значения логического выражения C, зависящего от x. Логическая семантика определяется формулой
LS(if (C) A else B) (x, y) (C Þ LS(A)(x, y)) & (ØC Þ LS(B)(x, y)) . (2.3)
Правильность построения логической семантики определяется сопоставлением с операционной семантикой языка программирования. Предикат RUN(S, x, y) обозначает следующее утверждение: существует такое исполнение конструкции S для набора значений x, которое завершается, и результатом исполнения является набор значений y. Данное определение допускает неоднозначность при исполнении S: в результате исполнения может быть получен другой набор y’, отличный от y.
Для конструкции S определим свойство согласованности (consistency) Cons(S): предикат LS(S) является истинным на наборах значений x и y тогда и только тогда, когда существует исполнение S для набора x, завершающееся вычислением набора значений y. Формально:
Cons(S) x y (LS(S)(x, y) RUN(S, x, y)) . (2.4)
Логическая семантика согласована с операционной семантикой, если свойство согласованности истинно для всех конструкций языка программирования.
Логическая и операционная семантика языка CCP и доказательство согласованности двух семантик описываются в следующем разделе.
Логическая семантика очевидным образом определяется для языков логического программирования. Однако в этом нет необходимости, поскольку логические формулы, входящие в программу, трактуются в общеизвестном математическом смысле. Построение логической семантики оказывается полезным лишь для нелогических особенностей логического программирования, таких как ситуация «неудачи» при ложном значении в Прологе; описание семантики с учетом данных особенностей дается в четырехзначной логике [14]. Логическая семантика может быть определена для языка предикативного программирования Э. Хехнера [15]. Программа там строится как результат последовательного уточнения (refinement) спецификации программы в виде логической формулы. Уточнения реализуются применением системы правил логического вывода.
Логическая семантика может быть построена для чистых 5 языков функционального программирования. Каждой конструкции языка функционального программирования можно сопоставить эквивалентную формулу на языке исчисления предикатов. Проблематично построение логической семантики для императивных языков. В логической формуле LS для оператора S кроме переменных, явно встречающихся в операторе S, должны участвовать другие переменные, определяющие состояние памяти исполняемой императивной программы.