我有这个方法来测试半群的结合性
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"}
""
可以看到,Fun
的Show
实例比简单地返回一个常量String
提供了更多的信息,就像Combine
的实例那样。