达夫尼:带有约束的类型

时间:2017-02-16 15:18:09

标签: dafny

我在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,它允许你对某些类型的变量设置一些约束,但这只适用于数字类型。

1 个答案:

答案 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