Module 模块中的Dafny export子句

Module 模块中的Dafny export子句,module,export,dafny,Module,Export,Dafny,在模块B中激活任何已注释的导出子句都会使导入的函数f对于模块B来说是未知的。有什么帮助吗?错误消息有点混乱,或者至少很微妙。取消对两个export K…声明之一的注释会产生以下两个错误: module A { export S reveals f export M provides g function f (x:int):int {x+1} function g (x:int):int {x-1} } module B { imp

在模块B中激活任何已注释的导出子句都会使导入的函数f对于模块B来说是未知的。有什么帮助吗?

错误消息有点混乱,或者至少很微妙。取消对两个
export K…
声明之一的注释会产生以下两个错误:

module A {
    export S reveals f
    export M provides g

    function f (x:int):int
    {x+1}

    function g (x:int):int
    {x-1}

}

module B {
    import opened A`{S,M}

    //export K reveals k

    //export K provides k

    function k (x:int):int
        requires f(x) == 0
    {x*2}

}
让我解释一下。我将重点关注
出口K提供的K
申报;另一个类似

通过声明导出集,模块将其声明的子集提供给模块的导入器。
提供
子句将声明的“签名”放入导出集中,而
揭示
子句将声明的“签名”和“正文”放入导出集中。对于函数,声明的“签名”包括函数的类型签名以及函数的规范。因此,示例中的
提供k
子句本质上是说导出
k
声明的以下部分:

This export set is not consistent: K

Raised while checking export set K: unresolved identifier: f
这里需要注意的是,声明的这一部分还提到了
f
。(这同样适用于带有
显示k
的出口报关单)

导出集必须是自一致的。这意味着导出声明中提到的所有内容(更准确地说,导出声明的导出部分--“签名”或“签名+正文”)必须分别有意义。特别是,这意味着导出部分中提到的每个符号(这里,在
k
的前提下提到
f
)也必须是导出集的一部分

所以,问题是您试图导出
k
,而不是
f
。如果在模块
B
中声明了
f
,您就知道该怎么做了:只需将
f
添加到导出集的
提供
子句中。但是在您的例子中,
f
是在模块
A
中声明的,而不是在
B
中声明的。这似乎是个问题,因为模块
B
中的导出集只允许导出
B
中定义的符号

这个问题有一个简单的解决办法。为了更清楚地解释,让我暂时将您的模块
B
更改一点:

function k (x:int):int requires f(x) == 0
在这里,我只导入
A`S
(而不是
A`m
),我显式地显示
A`S
(即
A
)的本地名称,并且省略了
opened
关键字。由于我省略了
opened
关键字,我还必须限定
k
规范中提到的
f
(编写
A.f
而不仅仅是
f

好的,在这个模块
B
中,导出集
K
仍然不一致,因为它试图提供
K
,而不提供
A.f
。更准确地说,第二条错误消息现在表示
A
未解决。这很好,因为(本地名称)
A
B
中声明,这意味着我们可以导出它。要解决此问题,只需将
添加到导出集即可提供一个

module B {
  import A = A`S
  export K provides k
  function k (x:int):int requires A.f(x) == 0 {x*2}
}
这使得导出集
K
一致,因为
K
的声明(“签名”部分)中提到的每个符号都是可见的。
K
不必直接导出
f
,因为
f
.f
提到为
a
的成员,并且导出了
a

让我们通过四个步骤回到您的示例

作为第一步,让我们将我的
import
声明更改为导入
a
的导出集、
s
M

export K provides k, A
在这里,我仍然显式地显示本地名称
A

作为第二步,让我们重新添加
opened
关键字:

import A = A`{S,M}
这使得可以将导入的声明称为合格声明(如
A.f
)或不合格声明(仅
f

作为第三步,让我们利用以下事实:在
B
中,我们可以将
f
称为不合格:

import opened A = A`{S,M}
作为返回示例的第四步也是最后一步,让我们在
import
声明中省略显式的本地名称
a
。默认本地名称与导入的模块相同,即
A
。现在,我们有以下无错误程序:

function k (x:int):int requires f(x) == 0 {x*2}
我希望这有帮助

鲁斯坦

module B {
  import opened A`{S,M}
  export K provides k, A
  function k (x:int):int requires f(x) == 0 {x*2}
}