我认为这会创建长度为3的任意列表,但是如何创建任意长度的列表?
import Test.QuickCheck
data List a =
Nil
| Cons a (List a)
deriving (Eq, Show)
instance Arbitrary a => Arbitrary (List a) where
arbitrary = do
a <- arbitrary
a' <- arbitrary
a'' <- arbitrary
return $ (Cons a (Cons a' (Cons a'' (Nil))))
答案 0 :(得分:7)
sized
。它使您能够管理生成的arbitrary
的大小,尽管语义取决于实例:
instance Arbitrary a => Arbitrary (List a) where
arbitrary = sized go
where go 0 = pure Nil
go n = do
xs <- go (n - 1)
x <- arbitrary
return (Cons x xs)
为了进行比较,这里是[]
的{{3}}:
instance Arbitrary a => Arbitrary [a] where
arbitrary = sized $ \n ->
do k <- choose (0,n)
sequence [ arbitrary | _ <- [1..k] ]
答案 1 :(得分:4)
您可以使用oneof
选择空列表或递归生成更长的列表:
instance Arbitrary a => Arbitrary (List a) where
arbitrary =
oneof [nil, cons]
where nil = return Nil
cons = do
h <- arbitrary
tl <- arbitrary
return $ Cons h tl
这里有一些测试:
λ> generate (arbitrary :: Gen (List Int))
Nil
λ> generate (arbitrary :: Gen (List Int))
Cons 4 (Cons 26 Nil)
λ> generate (arbitrary :: Gen (List Int))
Nil
备注
zeta指出,这有一个明显的缺陷,你可能会产生非常短的列表:
Cons
Nil)= 0.25 Cons
_ Cons
Nil)= 0.125 因为它会以概率0.5
绘制Nil
Zetas解决方案没有这个问题!
如果您愿意,可以使用frequency
代替oneof
来调整这些概率:
frequency [(1,nil), (4,cons)]
在这里,您将拥有p(Nil) = 0.2
和p(Cons) = 0.8
,但当然您可以根据自己的喜好进行调整。
另一种方法是认识到List a
与[a]
是同构的,并将Arbitrary
实例重用于列表:
instance Arbitrary a => Arbitrary (List a) where
arbitrary = toList <$> arbitrary
谢谢Zeta