可以使用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指出,這有你明顯的缺陷病產生可能非常短列表:
- P(無)= 0.5
- P((_
Cons
無)= 0.25
- P((_ _
Cons
Cons
無)= 0.125
- .. 。
,因爲它會繪製Nil
概率0.5
齊塔溶液不甲肝這個問題!
你可以通過使用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
感謝澤塔
鑑於'oneOf'會最有可能對列表中的所有元素使用相同的概率,只有50%的機會獲得非空列表,只有25%獲得一個元素的列表,12.5%獲得包含兩個元素的列表,等等上。如果你想要這樣的行爲(例如用概率'2 **(-n + 1)'生成一個長度爲'n'的列表,那沒問題,但總的來說,這會導致短列表。 – Zeta
是的,這是真的你的解決方案顯然更好,已經被接受 - 所以你想讓我刪除它嗎? – Carsten
Nah,但也許你可以找到一種替代方法來生成更長的列表,例如'toList :: [a] - >列表a'和'任意=列表<$>任意',作爲與[[a]同構的類型的示例。 – Zeta