模块中的Dafny导出子句

时间:2018-06-20 18:05:09

标签: module export dafny

Hyperlinks

激活模块B中的任何带注释的export子句会使模块B未知导入的函数f。有帮助吗?

1 个答案:

答案 0 :(得分:0)

错误消息有点混乱,或者至少是微妙的。对两个export K ...声明中的任何一个取消注释都会产生以下两个错误:

This export set is not consistent: K

Raised while checking export set K: unresolved identifier: f

让我解释一下。我将重点介绍export K provides k声明;另一个是相似的。

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

function k (x:int):int requires f(x) == 0

此处要注意的相关事项是,声明的这一部分还提到了f。 (对于使用reveal k的导出声明也是如此。)

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

因此,问题在于您尝试导出k,而不是f。如果在模块{{1}中声明了f,您将知道该怎么做:只需将B添加到导出集的f子句中。但是对于您来说,provides是在模块f中声明的,而不是在A中声明的。这似乎是一个问题,因为模块B中的导出集仅允许导出B中定义的符号。

问题有一个简单的解决方案。为了更清楚地说明这一点,让我临时更改一下模块B

B

在这里,我仅导入module B { import A = A`S export K provides k function k (x:int):int requires A.f(x) == 0 {x*2} } (而不是A`S),我明确显示了A`M(即A`S)的本地名称,省略了A关键字。由于我省略了opened关键字,因此我还必须限定opened的规范中对f的提及(写k而不只是A.f)。

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

provides A

这使导出集export K provides k, A 保持一致,因为K声明的(“签名”部分中提到的每个符号都是可见的)。 k不必直接导出K,因为f提到{{1}是f的成员,而.fA的成员。导出。

让我们以四个步骤回到您的示例。

第一步,让我们更改A声明,以同时导入importA的两个导出集:

S

在这里,我仍在明确显示本地名称M

第二步,让我们重新添加import A = A`{S,M} 关键字:

A

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

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

B

作为第四步,也是最后一步,请回到示例中,在f声明中省略显式的本地名称function k (x:int):int requires f(x) == 0 {x*2} 。默认本地名称与要导入的模块相同,即A。现在,我们有以下无错误程序:

import

我希望这会有所帮助。

Rustan