在达夫尼用另一张地图更新地图

时间:2018-10-02 14:23:13

标签: dafny

我想在Dafny中编写以下函数,该函数使用来自m1的所有映射更新映射m2,以使m2覆盖m1

function update_map<K, V>(m1: map<K, V>, m2: map<K, V>): map<K, V>
ensures
  (forall k :: k in m2 ==> update_map(m1, m2)[k] == m2[k]) &&
  (forall k :: !(k in m2) && k in m1 ==> update_map(m1, m2)[k] == m1[k]) &&
  (forall k :: !(k in m2) && !(k in m1) ==> !(k in update_map(m1, m2)))
{
  map k | (k in m1 || k in m2) :: if k in m2 then m2[k] else m1[k]
}

我遇到以下错误:

Dafny 2.2.0.10923
stdin.dfy(7,2): Error: a map comprehension involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of 'k' (perhaps declare its type, 'K', as 'K(!new)')
stdin.dfy(7,2): Error: a map comprehension must produce a finite set, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'k'
2 resolution/type errors detected in stdin.dfy

我不明白第一个错误,第二个错误是,如果m1m2都具有有限域,那么它们的并集当然也是有限的,但是我该如何解释呢?达芙妮?

更新:

应用James的修复程序后,它会起作用:

function update_map<K(!new), V>(m1: map<K, V>, m2: map<K, V>): map<K, V>
ensures
  (forall k :: k in m1 || k in m2 ==> k in update_map(m1, m2)) &&
  (forall k :: k in m2 ==> update_map(m1, m2)[k] == m2[k]) &&
  (forall k :: !(k in m2) && k in m1 ==> update_map(m1, m2)[k] == m1[k]) &&
  (forall k :: !(k in m2) && !(k in m1) ==> !(k in update_map(m1, m2)))
{
  map k | k in (m1.Keys + m2.Keys) :: if k in m2 then m2[k] else m1[k]
}

1 个答案:

答案 0 :(得分:2)

好问题!您正遇到Dafny中一些已知的未充分记录的尖锐边缘。

在第一个错误中,Dafny基本上是在说类型变量K必须限制为不是引用类型。您可以通过将函数签名更改为以

开头
function update_map<K(!new), V>...

在这里,(!new)是Dafny语法,恰恰意味着K只能用值类型实例化,而不能用引用类型实例化。 (不幸的是,!new尚未记录,但是有open issue与此相关。)

在第二个错误中,您正在违反Dafny有限的语法试探法来证明有限性,如本question and answer中所述。解决方法是使用Dafny的内置集合并运算符,而不是布尔析取,如下所示:

map k | k in m1.Keys + m2.Keys :: ...

(在这里,我使用.Keys将每个地图转换为其域中的键集,以便我可以应用+,该键可用于集合,但不适用于地图。)

在修复了这两个类型检查时间错误之后,您现在获得了两个新的验证时间错误。是的!

stdin.dfy(3,45): Error: element may not be in domain
stdin.dfy(4,59): Error: element may not be in domain

这些告诉您后置条件本身的语句格式不正确,因为您在使用键索引到映射时没有正确地假设这些键在映射的域中。您可以通过添加另一个后置条件(在其他条件之前 )来解决此问题,如下所示:

  (forall k :: k in m1 || k in m2 ==> k in update_map(m1, m2)) && ...

之后,整个函数将进行验证。