为什么可以在方法和函数中使用Hilbert epsilon运算符,但不能在“函数方法”中使用Hilbert epsilon运算符?
method choose<T>(s:set<T>) returns (x:T)
requires s != {}
{
var z :| z in s;
return z;
}
function choose'<T>(s:set<T>):T
// function method choose'<T>(s:set<T>):T // Activate this line and comment the previous line to see the error
requires s != {}
{
var z :| z in s;
z
}
答案 0 :(得分:0)
为了Hilbert epsilon运算符(在Dafny中也称为let-such-that表达式),
var z :| P; E
要编译,约束P
必须唯一地确定z
。在您的情况下,约束P
是z in s
,除了单例集之外,它不能唯一地确定z
。
如果s
的类型为set<int>
,则可以通过将choose'
函数更改为以下方式来(低效地)满足此要求:
function method choose'<T>(s:set<int>):int
requires s != {}
{
var z :| z in s && forall y :: y in s ==> z <= y;
z
}
差不多。您需要说服Dafny有这样的z
。您可以在引理中做到这一点。这是一个可能比需要的时间长的东西,但是我要做的第一个事情是。请注意,引理也使用Hilbert运算符,但是在语句上下文中,因此唯一性要求不适用。
function method choose'<T>(s:set<int>):int
requires s != {}
{
HasMinimum(s);
var z :| z in s && forall y :: y in s ==> z <= y;
z
}
lemma HasMinimum(s: set<int>)
requires s != {}
ensures exists z :: z in s && forall y :: y in s ==> z <= y
{
var z :| z in s;
if s == {z} {
// the mimimum of a singleton set is its only element
} else if forall y :: y in s ==> z <= y {
// we happened to pick the minimum of s
} else {
// s-{z} is a smaller, nonempty set and it has a minimum
var s' := s - {z};
HasMinimum(s');
var z' :| z' in s' && forall y :: y in s' ==> z' <= y;
// the minimum of s' is the same as the miminum of s
forall y | y in s
ensures z' <= y
{
if
case y in s' =>
assert z' <= y; // because z' in minimum in s'
case y == z =>
var k :| k in s && k < z; // because z is not minimum in s
assert k in s'; // because k != z
}
}
}
很遗憾,您的s
的类型不是set<int>
。我不知道如何从通用集合中获得唯一值。 :(
有关为何唯一性要求在编译表达式中如此重要的信息,请参见this paper。
Rustan
答案 1 :(得分:0)
好的,谢谢,我理解非唯一确定值的编译问题。 但是,根据您的回答,我的第一个方法select应该引发与函数方法select'相同的错误,不是吗?
method choose<T>(s:set<T>) returns (x:T)
requires s != {}
{
var z :| z in s;
return z;
}
function choose'<T>(s:set<T>):T
// function method choose'<T>(s:set<T>):T // Activate this line and comment the previous line to see the error
requires s != {}
{
var z :| z in s;
z
}