Дафни

редактировать
Дафни
Парадигма Императив, Функциональный
Разработан К. Рустан М. Лейно
Разработчик Microsoft Research
Впервые появилось2009 г.; 11 лет назад (2009 г.)
Стабильный выпуск 2.3.0 / 7 мая 2019 г.; 17 месяцев назад (2019-05-07)
Печатная дисциплина Статическая, сильная, безопасная
Лицензия Лицензия MIT
Веб-сайтисследование.microsoft.com / dafny

Dafny - это императивный скомпилированный язык, предназначенный для C # и поддерживающий предварительные условия формальных спецификаций с по , постусловия, инварианты цикла и варианты цикла. Язык сочетает в себе идеи в основном из функциональной и императивной парадигм и включает ограниченную поддержку объектно-ориентированного программирования. Возможности включают универсальные классы, динамическое размещение, индуктивные типы данных и разновидность логики разделения, известную как неявные динамические кадры для рассуждений о побочных эффектах. Dafny был создан Рустаном Лейно из Microsoft Research после его предыдущей работы по разработке ESC / Modula-3, ESC / Java и Spec #. Dafny широко используется в обучении и регулярно участвует в соревнованиях по проверке программного обеспечения (например, VSTTE'08, VSCOMP'10, COST'11 и VerifyThis'12).

Дафни был разработан, чтобы обеспечить простое введение в формальную спецификацию и проверку, и широко использовался в обучении. Dafny построен на промежуточном языке Boogie , который использует автоматическое средство доказательства теорем Z3 для выполнения обязательств по доказательству.

Содержание
  • 1 Типы данных
  • 2 Императивные функции
  • 3 Инварианты цикла
  • 4 Функции проверки
  • 5 Ссылки
  • 6 Внешние ссылки
Типы данных

Dafny предоставляет методы для реализации, которые могут иметь побочные эффекты и функции для использования в спецификации чистый. Методы состоят из последовательностей операторов, соответствующих знакомому императивному стилю, тогда как тело функции, напротив, является просто выражением. Любые побочные инструкции в методе (например, присвоение элемента параметра массива) должны быть учтены, отмечая, какие параметры могут быть изменены в предложении модифицирует. Dafny также предоставляет ряд неизменяемых типов коллекций, включая: последовательности (например, seq), наборы (например, set) и карты (map ). Кроме того, предоставляются изменяемые массивы (например, array).

Императивные особенности

Дафни поддерживает доказательства императивных программ, основанные на идеях логики Хоара. Ниже показано множество таких функций в Dafny, включая использование предварительных условий, постусловий, инвариантов цикла и вариантов цикла.

method max (arr: array ) returns (max: int) // В массиве должен быть хотя бы один элемент, требуется arr! = Null arr.Length>0; // Возвращаемое значение не может быть меньше, чем гарантирует любой элемент в массиве (forall j: int :: (j>= 0 j < arr.Length ==>max>= arr [j])); // Возврат должен соответствовать некоторому элементу в массиве гарантирует (существует j: int :: j>= 0 j < arr.Length max==arr[j]); { max:=arr[0]; var i:int :=1; // while(i < arr.Length) // Indent at most arr.Length (needed to show i==arr.Length after loop) invariant (i<=arr.Length); // No element seen so far larger than max invariant (forall j:int :: j>= 0 j max>= arr [j]); // Некоторый видимый элемент соответствует максимальному инварианту (существует j: int :: j>= 0 j max) {max: = arr [i];} // Продолжаем через массив i: = i + 1; }}

В этом примере вычисляется максимальный элемент массива. Предусловие и постусловие метода задаются с помощью предложений requiresи requires(соответственно). Аналогично, инвариант цикла и вариант цикла задаются с помощью предложений инварианти уменьшения(соответственно).

Инварианты цикла

Обработка инвариантов цикла в Dafny отличается от традиционной логики Хоара. Переменные, измененные в цикле, обрабатываются таким образом, что (большая часть) информации, известной о них до цикла, отбрасывается. Информация, необходимая для доказательства свойств таких переменных, должна быть явно выражена в инварианте цикла. Напротив, переменные, не измененные в цикле, сохраняют всю информацию, известную о них заранее. Следующее обеспечивает иллюстрацию:

метод sumAndZero (ns: array ) возвращает (sum: nat) требует ns! = Null требуется для всех i :: 0 <= i < ns.Length ==>ns [i]>= 0 изменяет ns {var i : int: = 0; var arr: array : = ns; // потому что параметры не могут быть присвоены sum: = 0; // while (i < arr.Length) { sum := sum + arr[i]; arr[i] := arr[i]; i := i + 1; } }

Проверка не пройдена, потому что Дафни не может установить, что (sum + arr [i])>= 0выполняется при присваивании. Из предварительного условия интуитивно понятно, что forall i: : 0 <= i < arr.Length ==>arr [i]>= 0сохраняется в цикле, поскольку arr [i]: = arr [i];является NOP. Однако это присвоение заставляет Дафни рассматривать arrкак изменяемую переменную и отбрасывать информацию, известную о ней до цикла. Чтобы проверить эту программу в Dafny, мы можем: удалить избыточное присвоение arr [i ]: = arr [i];; или добавьте инвариант цикла , инвариант forall i :: 0 <= i < arr.Length ==>arr [i]>= 0

Дафни дополнительно использует ограниченный статический анализ, чтобы вывести простые инварианты цикла, где это возможно. В приведенном выше примере может показаться, что инвариант цикла инвариант i>= 0также требуется, поскольку переменная iизменяется внутри Цикл. Хотя базовая логика требует наличия такого инварианта, Дафни автоматически делает это, и, следовательно, его можно опустить на уровне источника.

Доказательство f Функции

Dafny включает функции, которые дополнительно поддерживают его использование в качестве помощника по проверке. Хотя доказательства простых свойств внутри функцииили метода(как показано выше) не являются чем-то необычным для инструментов такого рода, Dafny также позволяет доказывать свойства между одной функцией и другое. Как обычно бывает с помощником по доказательству, такие доказательства часто имеют индуктивный характер. Дафни, возможно, необычен в использовании вызова метода в качестве механизма для применения индуктивной гипотезы. Ниже показано:

список типов данных = Nil | Link (data: int, next: List) function sum (l: List): int {match l case Nil =>0 case Link (d, n) =>d + sum (n)} predicate isNatList (l: List) {match l case Nil =>true case Link (d, n) =>d>= 0 isNatList (n)} Призрачный метод NatSumLemma (l: List, n: int) требует isNatList (l) n == sum ( l) гарантирует, что n>= 0 {соответствует l case Nil =>// Разряжается автоматически case Link (data, next) =>{// Применить индуктивную гипотезу NatSumLemma (next, sum (next)); // Проверяем, что известно Dafny assert data>= 0; }}

Здесь NatSumLemmaдоказывает полезное свойство между sum ()и isNatList ()(то есть, что isNatList (l) ==>(сумма (l)>= 0)). Использование метода-призракадля кодирования лемм и теорем является стандартным в Dafny с рекурсией, применяемой для индукции (обычно, структурная индукция ). Анализ случаев выполняется с использованием операторов match, а неиндуктивные случаи часто удаляются автоматически. Верификатор также должен иметь полный доступ к содержимому функции или предиката, чтобы при необходимости развернуть их. Это имеет значение при использовании вместе с модификаторами доступа. В частности, скрытие содержимого функции с помощью модификатора protectedможет ограничить, какие свойства могут быть установлены для нее.

Ссылки
Внешние ссылки
Последняя правка сделана 2021-05-16 10:11:10
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте