попытка свидетеля null: результат операции может нарушить ограничение типа подмножества

Я написал класс, представляющий бинарное отношение в наборе S с двумя полями: этот набор S и второй набор пар значений, взятых из S. Класс определяет набор свойств отношений, таких как быть однозначным (т. е. быть функцией, как определено в предикате "isFunction()"). После определения класса я пытаюсь определить некоторые типы подмножеств. Один из них предназначен для определения подтипа этих отношений, которые на самом деле также являются «функциями». Это не работает, и немного сложно расшифровать полученные коды ошибок. Обратите внимание, что предикаты Valid() и isFunction() объявляют «читает это;». Любые идеи о том, где я должен искать? Это из-за того, что Дафни не может сказать, что тип подмножества обитаем? Есть ли способ убедить его, что это так?

    type func<T> = f: binRelOnS<T> | f.Valid() && f.isFunction()

[Dafny VSCode] попытка свидетеля null: результат операции может нарушить ограничение типа подмножества для 'binRelOnS'


person Kevin S    schedule 01.03.2018    source источник
comment
В современном Dafny имена классов относятся к ненулевому варианту класса. Вы можете сказать binRelOn?, чтобы разрешить возможность null. К сожалению, я не думаю, что есть какой-то другой способ создать свидетеля.   -  person James Wilcox    schedule 01.03.2018
comment
Когда я добавляю? (т. е. когда я использую binRelOnS? в качестве базового типа) Дафни жалуется на это: не может найти свидетеля, который показывает, что тип обитаем (пробовал только null); попробуйте дать подсказку через пункт «свидетель» или «призрачный свидетель». Я не нашел документации по концепции оговорки о свидетелях и/или призрачных свидетелях (только два поиска в Google). Был бы рад предоставить больше контекста, если это поможет.   -  person Kevin S    schedule 05.03.2018


Ответы (1)


Типы подмножеств и непустота

Определение типа подмножества формы

type MySubset = x: BaseType | RHS(x)

вводит MySubset как тип, обозначающий те значения x типа BaseType, которые удовлетворяют логическому выражению RHS(x). Поскольку каждый тип в Dafny должен быть непустым, существует обязанность доказательства, чтобы показать, что объявленный вами тип имеет некоторый член. Дафни может найти несколько значений-кандидатов и попытается проверить, удовлетворяет ли какое-либо из них RHS. Если кандидаты этого не сделают, вы получите сообщение об ошибке, похожее на то, которое вы видели. Иногда в сообщении об ошибке будет указано, какие значения-кандидаты пробовала Дафни.

В вашем случае единственным значением-кандидатом, которое пробовал Дафни, является значение null. Как указывает Джеймс, значение null даже не достигает первой базы, потому что BaseType в вашем примере является типом ненулевых ссылок. Если вы измените binRelOnS<T> на binRelOnS?<T>, то null имеет шанс быть возможным свидетелем того, что ваш тип подмножества непуст.

Свидетели, предоставленные пользователем

Поскольку Дафни не слишком умен в выборе кандидатов в свидетели, возможно, вам придется предоставить их самостоятельно. Вы делаете это, добавляя предложение witness в конце объявления. Например:

type OddInt = x: int | x % 2 == 1 witness 73

Поскольку 73 удовлетворяет ограничению RHS x % 2 == 1, Дафни принимает этот тип. В некоторых программах может случиться так, что свидетель, который вы имеете в виду, доступен только в фантомном коде. Затем вы можете написать ghost witness вместо witness, что позволит последующему выражению быть призрачным. Свидетель-призрак можно использовать для убеждения верификатора Dafny в том, что тип непустой, но он не помогает компилятору Dafny инициализировать переменные этого типа, поэтому вам все равно придется инициализировать такие переменные самостоятельно.

Используя предложение witness, вы можете попытаться предоставить свой собственный свидетель, используя исходное определение типа подмножества func. Однако предложение свидетеля принимает выражение, а не оператор, что означает, что вы не можете использовать new. Если вы не заботитесь о компиляции своей программы и готовы доверять себе в существовании свидетеля, вы можете объявить функцию без тела, которая обещает вернуть подходящий свидетель:

type MySubset = x: BaseType | RHS(x) ghost witness MySubsetWitness()

function MySubsetWitness(): BaseType
  ensures RHS(MySubsetWitness())

Вам понадобится либо ghost witness, либо function method. Функция MySubsetWitness навсегда останется без тела, так что у вас есть возможность ошибиться относительно некоторого значения, удовлетворяющего RHS.

Предложение witness было введено в Dafny версии 2.0.0. В примечаниях к выпуску 2.0.0 это упоминается, но, по-видимому, не дать много объяснений. Если вы хотите увидеть больше примеров witness, найдите это ключевое слово в наборе тестов Dafny< /а>.

Типы подмножеств классов

В вашем примере, если вы измените базовый тип на возможно нулевой ссылочный тип:

type func<T> = f: binRelOnS?<T> | f.Valid() && f.isFunction()

тогда ваша следующая проблема будет заключаться в том, что RHS разыменовывает f. Вы можете исправить это, ослабив ограничение типа подмножества следующим образом:

type func<T> = f: binRelOnS?<T> | f != null ==> f.Valid() && f.isFunction()

Теперь наступает часть, которая может стать нарушителем сделки. Типы подмножества не могут зависеть от изменяемого состояния. Это связано с тем, что типы — очень статичное понятие (в отличие от спецификаций, которые часто зависят от состояния). Было бы катастрофой, если бы значение могло удовлетворять типу в один момент, а затем, после некоторого изменения состояния в программе, не удовлетворять типу. (Действительно, почти все системы типов с подмножеством/уточнением/зависимыми типами предназначены для функциональных языков.) Таким образом, если ваши предикаты Valid или isFunction имеют предложение reads, то вы не сможете определить func так, как надеялись. Но поскольку и Valid, и isFunction зависят только от значений const полей в классе, то предложение reads не требуется, и все готово.

Рустан

person Rustan Leino    schedule 06.03.2018