证明/测试通用函数的正确性

时间:2013-11-28 08:15:52

标签: generics haskell quickcheck

(这不是关于定理证明是关于实践中的测试,如quickCheck

f使用一些通用函数

f :: RESTRICTIONS => GENERICS

与一些"理想的"属性(即不是hack,是不可变的,......)通常是纯Haskell泛型函数。

假设我们想测试它,主要问题是

如果我们(已经)测试了一个特定类型的函数(例如Int),我们可以假设它对所有类型都是正确的吗?(当然,匹配限制)< / p>

(&#34;经过良好测试&#34;我的意思是&#34;所有&#34;功能{domain X properties}已经过测试)

理论上我们可以确定但是,我不确定在实例化过程(即编译)中是否有一些额外的属性,限制......可能会产生影响。

谢谢!

注意测试可能使用某些特定类型的属性(例如Int),但这些属性不能成为测试属性的一部分。例如。如果Monoid是一个限制,那么关联性可以成为测试属性的一部分(但如果不是限制,则不是交换性)。

示例

f

repeatedHeader :: Eq a => [a] -> Bool
repeatedHeader (x:y:_) = x == y
repeatedHeader _ = False

test1 = repeatedHeader [1,1,2] == True
test2 = repeatedHeader [1,2,3] == False

2 个答案:

答案 0 :(得分:2)

您可以确定只有在简单的情况下RESTRICTIONS为空或者至少没有提及相关的泛型类型。

在所有其他情况下,您的函数取决于类类实例的功能。但即使所有现有的实例都按照您期望的方式运行,对于明天编写的类型类实例也不一定如此。

因此,这是在实例中强制执行某些属性的问题。这通常是一个弱点,因为类型类法律大多只是非正式地陈述。例如,Haskell不能也不会阻止您制作有缺陷的Eq或Ord实例。

真实世界的例子是对以下函数的测试:

f :: Num a => a -> a

现在,我们知道我们确实拥有静默溢出的类型,比如Int。其他人没有。这在Num课堂中是默默忍受的,因为,生活就是这样。因此,一旦您使用Double进行了所有测试,如果您在f上使用Int,您仍会感到惊讶。

答案 1 :(得分:1)

不,你不能确定。

考虑

f :: (Fractional a) => a -> a
f x = (2 * x^2 + 2) / (x^2 + 1)

你现在明确地说f x ≡ 2。果然,

  

前奏&GT;图f [-2,-1.6 .. 3]
  [2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0,2.0]

事实上,它确实适用于所有Rational个参数,以及任何非超限实数类型。但是当你允许更通用的Fractional类型时,它很容易被打破:

  

Prelude Data.Complex&gt; f(0:+ 1)
  NaN:+ NaN

关键点基本上是所有 1 Real类型都有额外的法则,特别是x^2 >= 0,这些法律不适用于一般的Num案例。


更好的例子可能是

g :: Num a => a -> a
g = (+1)

直观地,g x > x,它适用于所有Integer。但这实际上不一定是真的......

  

Prelude Data.Modular&gt; map(((x ::ℤ/ 5) - &gt; g x&gt; x)。fromInteger)[0 .. 10]
  [真,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE,TRUE,TRUE,FALSE,真]


1 对数字问题的反思,例如Double