我在Dafny尝试一些事情。我想编写一个简单的数据结构,在内存中保存一个未压缩的图像:
datatype image' = image(width: int, height: int, data: array<byte>)
newtype byte = b: int | 0 <= b <= 255
实际使用它:
method Main() {
var dat := [1,2,3];
var im := image(1, 3, dat);
}
datatype image' = image(width: int, height: int, data: array<byte>)
newtype byte = b: int | 0 <= b <= 255
让Dafny抱怨:
stdin.dfy(3,24):错误:数据类型构造函数参数类型不正确(找到seq,预期数组) 在stdin.dfy中检测到1个分辨率/类型错误
我可能还想要求字节数组不为空,并且字节数组的大小等于width * height * 3(存储表示该像素的RGB值的三个字节)。
我应该以何种方式强制执行此操作?我查看了newtype,它允许你对某些类型的变量设置一些约束,但这只适用于数字类型。
答案 0 :(得分:2)
Dafny支持不可变序列(类似于元素的数学序列)和可变数组(与C和Java一样,指向元素的指针)。您收到的错误告诉您,您正在使用image
值调用seq<byte>
构造函数,其值为array<byte>
。
您可以将dat
的定义替换为:
var dat := new byte[3];
dat[0], dat[1], dat[2] := 1, 2, 3;
然而,更典型的是,如果您使用数据类型(不可变),则使用序列。因此,您可能希望将image
的定义更改为:
datatype image = image(width: int, height: int, data: seq<byte>)
顺便说一句,请注意,Dafny允许你为一个类型和它的一个构造函数命名相同,所以没有理由用一个素数命名其中一个(当然除非你想要)。
另一种风格问题是在byte
:
newtype byte = b: int | 0 <= b < 256
由于半开放区间在计算机科学中很普遍,Dafny的语法对它们有利。例如,对于序列s
,表达式s[52..57]
表示从s
开始在索引52处的长度为5的s
的子序列(即,57减去52)。还有一件事,如果你愿意,你也可以省略int
b
类型,因为Dafny会推断它:
newtype byte = b | 0 <= b < 256
您还询问了添加类型约束的可能性,以便数据类型中的序列始终为3的长度。正如您所发现的,您不能使用newtype
执行此操作,因为{{1} (至少现在)只适用于数字类型。但是,您可以(几乎)使用子集类型。这将按如下方式完成:
newtype
(在这个例子中,第一个竖线与type triple = s: seq<byte> | |s| == 3
声明中的竖条相似,并且表示“如此”,而接下来的两个表示序列上的长度运算符。)此声明的问题在于类型必须是非空的,Dafny不相信有任何值满足newtype
的约束。嗯,达菲不是很努力。计划是在triple
(和witness
)声明中添加type
子句,以便程序员可以向Dafny显示属于newtype
类型的值。但是,此支持正在等待一些允许自定义初始值的实现更改,因此您目前无法使用此约束。
不是你想要它,但是Dafny会让你给出一个较弱的约束来承认空序列:
triple
所以,相反,如果你想谈论type triple = s: seq<byte> | |s| <= 3
值的长度为image
的组件,那么引入一个谓词:
data
并在预条件和后置条件等规范中使用此谓词。
安全编程,
Rustan