我希望下面的代码生成一个大小为1,2或3的列表生成器,每个元素都是独立生成的。
shortlist :: Arbitrary a => Gen [a]
shortlist = oneof $ map promote [[arbitrary],
[arbitrary, arbitrary],
[arbitrary, arbitrary, arbitrary]]
REPL:
sample (shortlist :: Gen [Char])
"\255\255\255"
"ii"
"FF"
"\236\236"
"FF"
"'''"
"8"
"HH"
"\160"
"\DEL\DEL\DEL"
"\246\246"
每个列表包含相同char的1,2或3个实例。为什么任意不符合预期?
答案 0 :(得分:6)
我真的不得不寻找promote
。 The module description表示该模块中提供的函数将重用随机数种子。您应该使用replicateM
或sequence
之类的内容,而不是使用promote
。
例如:
shortlist :: Arbitrary a => Gen [a]
shortlist = oneof $ map sequence [[arbitrary],
[arbitrary, arbitrary],
[arbitrary, arbitrary, arbitrary]]
或
shortlist :: Arbitrary a => Gen [a]
shortlist = oneof $ [ replicateM n arbitrary | n <- [1..3] ]
会产生类似的结果:
> sample (shortlist :: Gen [Char])
"\SI"
"aP"
"\153\US\STX"
"#k"
"U"
"}\DC1"
"i"
"\186F"
"\148k"
"\RS|\159"
"\192L"
答案 1 :(得分:6)
在QuickCheck-2.7.6中。 promote
已移至Test.QuickCheck.Gen.Unsafe模块。
那里的评论解释了你所看到的:
Gen只是道德上的monad:两个应该相等的生成器将给出相同的概率分布,但它们可能与随机数种子到值的函数不同。 QuickCheck保持了Gen是概率分布的假象,并且不允许您区分具有相同分布的两个生成器。
此模块中的功能允许您通过重复使用相同的随机数种子两次来打破这种错觉。这是不安全的,因为通过将相同的种子应用于两个道德上相等的发电机,您可以看出它们是否真的相同。