我正在研究Haskell Book并且已经为newType Comp
编写了一个任意实例。代码在
instance Show (Comp a) where
show f = "Unicorns!!"
newtype Comp a =
Comp { unComp :: (a -> a) }
instance (Semigroup a) => S.Semigroup (Comp a) where
(Comp fx) <> (Comp fy) = Comp (fx . fy)
instance (CoArbitrary a, Arbitrary a) => Arbitrary (Comp a) where
arbitrary = do
f <- Test.QuickCheck.arbitrary
return (Comp f)
type CompAssoc = String -> Comp String -> Comp String -> Comp String -> Bool
compAssoc :: (S.Semigroup a, Eq a) => a -> Comp a -> Comp a -> Comp a -> Bool
compAssoc v a b c = (unComp (a <> (b <> c)) $ v) == (unComp ((a <> b) <> c) $ v)
并使用
进行测试main :: IO ()
main = do
quickCheck (compAssoc :: CompAssoc)
我的问题围绕着任意实例。它正在生成一个传递给return (Comp f)
的函数。我理解(尽管不完全是为什么)这必须是CoArbitrary的范围。但如果传递给return (Comp f)
的内容是CoArbitrary
,那么它又如何Arbitrary
?我想似乎这些约束都指的是函数的传递/返回类型和函数本身。我有点困惑。
答案 0 :(得分:1)
这是初学者,高级,很可能在底层细节中不正确对Arbitrary
和{{之间关系的解释1}}。
文章https://begriffs.com/posts/2017-01-14-design-use-quickcheck.html为您提供了更好的解释,但它使用了Applicative和Functor,但我还没有到达那里,因为我仍然在#34; The Haskell Book&#34;
如果要从CoArbitrary
生成函数,a -> b
必须具有b
的实例。无论如何我们都会生成随机内容,因此我们需要像往常一样Arbitrary
。但是我们需要改变这个Gen b
就像普通函数一样,也就是说,如果我将一个不同的值传递给像b
这样的函数,I&# 39; d期待不同的回应。但是,我们怎样才能根据某些随机double
改变生成器?好吧,如果我们考虑一下我们首先生成随机a
的方式,它就与b
有关。即如果我想要一个随机numbers
(比如说Int),我只需要生成一个随机数。十分简单。随机字符串?从随机数开始,将它们转换为ASCII字符。与您想要的任何其他数据类型相同,并且quickcheck提供了许多{I}个实例。
b
进来的地方!如果我将某个类型标记为需要拥有Arbitrary
的实例,实际上我会说&#34;我需要能够将您的类型减少到一个数字,以便我可以变化(add / mult / etc)类型CoArbitrary
的生成器。因此,如果类型CoArbitrary
是一个字符串,例如,将该字符串减少为一个数字,将其传递给b
的gen,以便让类型为a
的Gen执行{ {1}}对用于生成type b
的数字进行操作。