有没有一种方法可以显示为quickCheck和quickBatch生成的值

时间:2020-01-27 16:18:52

标签: haskell quickcheck

我为此代码运行quickBatch测试:

data List a = 
    Nil 
  | Cons a (List a) 
  deriving (Eq, Show) 

instance Functor List where
  fmap _ Nil         = Nil
  fmap f (Cons a as) = Cons (f a) (fmap f as)

instance Applicative List where
  pure a = Cons a Nil
  Nil <*> _ = Nil
  _ <*> Nil = Nil
  (Cons f fs) <*> as = fmap f as `append` (fs <*> as)

append :: List a -> List a -> List a
append Nil ys         = ys
append (Cons x xs) ys = Cons x $ xs `append` ys

instance Arbitrary a => Arbitrary (List a) where
  arbitrary = frequency [(1, return Nil), (2, Cons <$> arbitrary <*> arbitrary)]

main :: IO ()
main =
  hspec $ do
    describe "List" $ do
      it "Functor" $
        property (quickBatch $ functor (undefined :: List (Int, Float, String)))
      it "Applicative" $
        property (quickBatch $ applicative (undefined :: List (Int, Float, String)))

当任意权重为1和2时,所有测试加在一起需要5秒才能完成。但是,当我将权重设置为1和499时(一次取零,而实际值取499次,对吗?),所有测试都变慢了,特别是每个适用成分测试需要5分钟。所以我想知道这种行为是从哪里来的,也许我能以某种方式看到生成的值。

1 个答案:

答案 0 :(得分:1)

我们可以计算具有 n 个元素的列表的概率分布。如果您实现它:

instance Arbitrary a => Arbitrary (List a) where
    arbitrary = frequency [(1, return Nil), (k, Cons <$> arbitrary <*> arbitrary)]

然后有 1 /(1 + k)列表终止。请注意,黑体字arbitrary是您在此处定义的任意值,因此您进行了 recursive 调用。因此,这意味着长度为 n 的列表的可能性为:

P(| L | = n)= k n-1 /(1 + k) n

这是Gemetrical distribution [wiki],列表的平均长度为 k (“几何分布”变量的平均值为 k + 1 ,但包括 Nil元素)。因此,这意味着,如果将 k 设置为499,则平均会生成499个元素的列表,而如果将k设置为2,它将会生成平均长度为2的列表。当然,计算量会根据列表的长度进行缩放。