Haskell 中的任意值
CoArbitrary in Haskell
我正在阅读 Haskell 这本书,并且已经到了为 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)
我的问题围绕着 Arbitrary 实例。它正在生成要传递给 return (Comp f)
的函数。我明白(虽然不完全是为什么)这必须限定在 CoArbitrary 范围内。但是传给return (Comp f)
的那个东西如果是CoArbitrary
,怎么可能也是Arbitrary
呢?我猜这些约束似乎都指的是函数的 pass/return 类型 和函数本身 。我有点困惑。
这是初学者的高级,很可能底层细节不正确对[=10=之间关系的解释] 和 CoArbitrary
。
文章 https://begriffs.com/posts/2017-01-14-design-use-quickcheck.html 给了你更好的解释,但它使用了 Applicative 和 Functor,我还没有到达那里,因为我还在 "The Haskell Book" 的 SemiGroup 章节。
如果要从 a -> b
生成函数,b
必须具有 Arbitrary
的实例。无论如何我们都会生成随机的东西,所以我们像往常一样需要 Gen b
。但是我们需要 vary 这个 b
就像普通函数一样,也就是说,如果我将不同的值传递给像 double
这样的函数,我希望得到不同的回应。但是我们如何改变一个基于随机a
的生成器呢?好吧,如果我们首先考虑我们生成随机 b
的方式,它与 numbers
有关。 IE。如果我想要一个随机的 b
(例如 Int),我只生成一个随机数。十分简单。随机字符串?从随机数开始,将它们转换为 ASCII 字符。与您想要的任何其他数据类型一样,quickcheck 提供了很多 Arbitrary
实例来做到这一点。
好的,所以最基本的是数字。
我们可以通过获取其他数字来更改这些数字,例如 multiplying/subtracting/adding/dividing。或任何其他数学运算。但是我们如何得到另一个数字呢?这就是 CoArbitrary
的用武之地!如果我将类型标记为需要 CoArbitrary
的实例,实际上我是在说“我需要能够将您的类型减少到一个数字,以便我可以 变化 (add/mult/etc) 类型 b
的生成器。因此,如果类型 a
是一个字符串,例如,将该字符串简化为一个数字,将其传递给 [=27] 的生成器=] 为了让类型 b
的 Gen 对 number(s) 执行 mult/add/etc
操作,它将用来生成 b
.
我正在阅读 Haskell 这本书,并且已经到了为 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)
我的问题围绕着 Arbitrary 实例。它正在生成要传递给 return (Comp f)
的函数。我明白(虽然不完全是为什么)这必须限定在 CoArbitrary 范围内。但是传给return (Comp f)
的那个东西如果是CoArbitrary
,怎么可能也是Arbitrary
呢?我猜这些约束似乎都指的是函数的 pass/return 类型 和函数本身 。我有点困惑。
这是初学者的高级,很可能底层细节不正确对[=10=之间关系的解释] 和 CoArbitrary
。
文章 https://begriffs.com/posts/2017-01-14-design-use-quickcheck.html 给了你更好的解释,但它使用了 Applicative 和 Functor,我还没有到达那里,因为我还在 "The Haskell Book" 的 SemiGroup 章节。
如果要从 a -> b
生成函数,b
必须具有 Arbitrary
的实例。无论如何我们都会生成随机的东西,所以我们像往常一样需要 Gen b
。但是我们需要 vary 这个 b
就像普通函数一样,也就是说,如果我将不同的值传递给像 double
这样的函数,我希望得到不同的回应。但是我们如何改变一个基于随机a
的生成器呢?好吧,如果我们首先考虑我们生成随机 b
的方式,它与 numbers
有关。 IE。如果我想要一个随机的 b
(例如 Int),我只生成一个随机数。十分简单。随机字符串?从随机数开始,将它们转换为 ASCII 字符。与您想要的任何其他数据类型一样,quickcheck 提供了很多 Arbitrary
实例来做到这一点。
好的,所以最基本的是数字。
我们可以通过获取其他数字来更改这些数字,例如 multiplying/subtracting/adding/dividing。或任何其他数学运算。但是我们如何得到另一个数字呢?这就是 CoArbitrary
的用武之地!如果我将类型标记为需要 CoArbitrary
的实例,实际上我是在说“我需要能够将您的类型减少到一个数字,以便我可以 变化 (add/mult/etc) 类型 b
的生成器。因此,如果类型 a
是一个字符串,例如,将该字符串简化为一个数字,将其传递给 [=27] 的生成器=] 为了让类型 b
的 Gen 对 number(s) 执行 mult/add/etc
操作,它将用来生成 b
.