函数上的QuickCheck半群



我有这个方法来测试半群的结合性

semigroupdAssoc :: (Eq m, Semigroup m) => m -> m -> m -> Bool
semigroupdAssoc a b c = a <> (b <> c) == (a <> b) <> c

给定以下类型

newtype Combine a b =
Combine { unCombine :: a -> b }

我的半群实现i

instance Semigroup b => Semigroup (Combine a b) where
(<>) (Combine u) (Combine u') = Combine (u <> u')

我被困在如何写一个快速测试,

假设我想测试String

type CombineAssoc = Combine String String -> Combine String String -> Combine String String -> Bool

测试将是

quickCheck (semigroupdAssoc :: CombineAssoc)

我知道我必须为Combine写一个Arbitrary实现,但我不知道怎么做。

我想出了解决办法,但是我不明白。

任意for Combine的实现如下:

instance (CoArbitrary a, Arbitrary b) => Arbitrary  (Combine a b) where
arbitrary = do
Combine <$> arbitrary

需要实现Show also(不是很好)

instance Show (Combine a b) where
show (Combine _) = "unCombine"

为这个数据类型更新关联函数

combineSemigroupAssoc :: (Eq b, Semigroup b) => a -> Combine a b -> Combine a b -> Combine a b -> Bool
combineSemigroupAssoc x a b c = unCombine (a <> (b <> c)) x == unCombine ((a <> b) <> c) x

实现需要测试的属性

genString :: Gen String
genString = arbitrary
prop_combineSemigroupAssoc :: Property
prop_combineSemigroupAssoc = forAll genString (combineSemigroupAssoc :: CombineAssoc)

最后运行quickCheck

quickCheck prop_combineSemigroupAssoc

认为我仍然需要帮助

  • 你能解释一下现在的任意实现是如何工作的吗(CoArbitrary的文档对我来说不是很清楚)?
  • 是否有更好的方法来实现Show for Combine,比如看到实际的调用参数?

我建议用Fun来写你的属性:

type SS = Fun String String -- just to shorten things a bit
prop_CombineAssoc :: SS -> SS -> SS -> String -> Bool
prop_CombineAssoc f_ g_ h_ s =
unCombine (f <> (g <> h)) s == unCombine ((f <> g) <> h) s
where
[f, g, h] = map (Combine . applyFun) [f_, g_, h_]

上面的属性通过了,但是为了好玩,下面是失败时的样子。为了得到这个输出,我将(f <> (g <> h))更改为f

> quickCheck prop_CombineAssoc
*** Failed! Falsified (after 3 tests and 16 shrinks):    
{_->""}
{_->""}
{_->"a"}
""

可以看到,FunShow实例比简单地返回一个常量String提供了更多的信息,就像Combine的实例那样。

相关内容

  • 没有找到相关文章

最新更新