我试图解决与"Haskell Programming from First Principles"第15章中的this other question相同的练习。我已经创建了一个Semigroup实例,并且在编写练习的QuickCheck部分时遇到了麻烦。如何测试此数据类型的半群法则?
半群实例应该满足:
a <> (b <> c) == (a <> b) <> c
<>
哪里是半群mappend。
我想出了以下内容:
import Data.Semigroup
import Test.QuickCheck
semigroupAssoc :: (Eq m, Semigroup m) => m -> m -> m -> Bool
semigroupAssoc a b c = (a <> (b <> c)) == ((a <> b) <> c)
newtype Combine a b = Combine { unCombine :: (a -> b) }
instance Semigroup b => Semigroup (Combine a b) where
(Combine f) <> (Combine g) = Combine (\x -> (f x) <> (g x))
instance CoArbitrary (Combine a b) where
coarbitrary (Combine f) = variant 0
instance (CoArbitrary a, Arbitrary b) => Arbitrary (Combine a b) where
arbitrary = do
f <- arbitrary
return $ Combine f
type CombineAssoc a b = Combine a b -> Combine a b -> Combine a b -> Bool
main :: IO()
main = do
quickCheck (semigroupAssoc :: CombineAssoc Int Bool)
一切编译除了quickCheck
线,在那里抱怨说有No instance for (Eq (Combine Int Bool)) arising from a use of ‘semigroupAssoc’
。
我不认为有一种方法可以测试两个任意函数是否相等(包含Combine
的函数),但练习文本表明这样的事情是可能的。
关于如何使这项工作的任何想法?
编辑:
作者给出一个提示本练习:
提示:此功能最终将应用于单值类型的 。但是,您将拥有多个可以生成类型b的 值的函数。我们如何组合多个值,所以我们有 单个b?这一个可能会很棘手!请记住,组合内的值的 类型是函数的值。如果你 找不到CoArbitrary,不要担心这个问题QuickChecking 。
@李霞瑶的回答似乎是最好的答案。但是,我不应该使用这个CoArbitrary实例来做什么吗?
最新的QC支持版本[功能](https://hackage.haskell.org/package/QuickCheck-2.9.2/docs/Test-QuickCheck-Function.html),但你必须改变你的type - 'newtype Combine'fun ab = Combine(fun ab);键入Combine = Combine'( - >);类型Combine_Test = Combine'Fun'(或创建一个复制结构的独特类型,但用'Fun'替换' - >') – user2407038
虽然对于这个例子他们希望你总体上使用'quickCheck',使用lambda演算可以减少函数一般证明平等。 –