如何在Haskell Test.QuickCheck中有效地生成随机测试

时间:2017-02-28 19:06:33

标签: haskell testing random quickcheck

我想使用Haskell Test.QuickCheck

生成一些示例测试

目标是使用以下条件生成(Int,[Int])的数据,其中元组是(x,xs):

  1. x> 0
  2. x不在xs
  3. 所有xs> 0
  4. 在一段时间后,我可以抓住我的头并绊倒手册{​​{3}},我可以制作符合这些要求的随机列表:

    import Test.QuickCheck
    mygen = arbitrary::Gen (Int, [Int]))
    sample (mygen `suchThat` ( \(x, xs)->( (x `notElem` xs) && (x > 0) && (all (>0) xs)&& (xs/=[]))))
    

    在GHCI中运行最后一行输出如下:

    (40,[19,35,27,29,45,1,17,28])
    (20,[3,9,11,12,15,8])
    (43,[76,102,106,71,24,2,29,101,59,48])
    (99,[5,87,136,131,22,22,133])
    (77,[11,14,55,47,78,15,14])
    ...
    

    问题:

    1. 如何更有效地完成这项工作,因为 - 我猜测 - mygen创建一个大样本集的函数然后根据suchThat标准过滤掉

    2. 如何指示列表xs应具有一定的大小。例如,如果我添加&& length xs > 50,程序会运行很长时间。

    3. 保证xs的每个元素都是唯一的。即避免像(99,[22,22])

    4. 这样的记录

1 个答案:

答案 0 :(得分:6)

是的,假设生成的数字为正数的概率是1/2,那么得到50个正数列表的概率是(1/2)^ 50,或1,125,899,906,842,624中的1。所以,是的,那不可能发生。

我建议不要生成列表并过滤它们,而是建议通过转换生成器来构建列表。

mygen :: Gen (Int, [Int])
mygen = do 
    x <- getPositive <$> arbitrary
    xs <- delete x <$> replicateM 50 (getPositive <$> arbitrary)
    return (x, xs)

现在,您可以立即获得符合条件的列表。

至于唯一性,请参阅Data.List.nub。您也可以考虑使用Data.Set,因为您似乎正在使用它。