签订合同“ true”,以使“ assert true x == x”成立

时间:2019-09-15 09:25:26

标签: haskell contract

是否可以编写合同来检查陈述是否正确? 例如,我想定义一个合同

true :: Contract a

使得对于所有值x,方程式

assert true x == x

按住。

我尝试过这样的事情:

true :: Contract a
true = Pred (\a -> True) 

但是在运行assert true x == x时,编译器会指出x是未定义的。 运行assert true 5==6时,结果为False,我希望有一个Contract violation error。 我应该如何更改此true合同?非常感谢您的帮助。

这里

data Contract :: * -> * where
  Pred :: (a -> Bool) -> Contract a
  Fun  :: Contract a -> Contract b -> Contract (a -> b)

如果违反合同,Assert将导致运行时失败,否则将返回原始结果:

assert :: Contract a -> a -> a
assert (Pred p)       x = if p x then x else error "contract violation"
assert (Fun pre post) f = assert post . f . assert pre

3 个答案:

答案 0 :(得分:6)

如果您考虑trueassert的定义,则可以很清楚地看到问题。以下是相关部分:

true :: Contract a
true = Pred (\a -> True) 

assert :: Contract a -> a -> a
assert (Pred p)       x = if p x then x else error "contract violation"
...

将它们放在一起,您会发现assert true x将测试(\a -> True) x并产生x或抛出错误,具体取决于它是True还是False 。而且无论您为True使用什么表达式,该值始终为x,因为根据定义,谓词始终返回True,而忽略其自变量。

简单的解决方法是让true“合同”实际测试其参数,如下所示:

true :: Contract Bool
true = Pred id

也就是说,这个新的true仅适用于类型Bool的值(因为它对其他任何值实际上都没有意义),并且对此无任何作用。如果值为True,它将使值保持不变,否则将引发您想要的违反合同错误:

Prelude> assert true (5==6)
*** Exception: contract violation
CallStack (from HasCallStack):
  error, called at <interactive>:21:46 in interactive:Ghci2
Prelude> assert true (5==5)
True

请注意assert true (5==6)中的括号,因为函数应用程序是Haskell中最先例的“运算符”,因此assert true 5==6被解析为(assert true 5)==6assert true 5==6导致错误,因为true的此更正版本仅适用于布尔值,因此不适用于5

答案 1 :(得分:0)

请注意,assert true x == xassert true xx进行比较;因此assert true 55,当然5 == 6为假,不是违反合同。

如果您打算assert true (x == x)保留,那么看起来

true :: Contract Bool
true = Pred id

assert true (5==6)  -- Contract violation

就是你想要的

答案 2 :(得分:0)

“在运行时断言true true x == x编译器说x是未定义的”在这里很关键。在我看来,您的assert调用是一个表达式,其中包含对x的两个引用,而最外面的函数是(==)。没有约束x的任何一方都无法评估。 assert true x部分再也看不到==,如果我们将其重写为assert true (x == x),我们仍然需要提供x :: Eq a。我不知道如何检查这样的函数,但是当然有些选项我不太熟悉。