można użyć oneof
odebrać albo pustą listę lub rekurencyjnie wygenerowania dłuższych list:
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
Oto kilka testów:
λ> generate (arbitrary :: Gen (List Int))
Nil
λ> generate (arbitrary :: Gen (List Int))
Cons 4 (Cons 26 Nil)
λ> generate (arbitrary :: Gen (List Int))
Nil
Uwagi
jako Zeta zauważyła, że ma ona oczywistą wadę choroby generowania prawdopodobnie bardzo krótkie listy:
- p (zero) = 0,5
- p ((_
Cons
ml) = 0,25
- p ((_ _
Cons
Cons
Nil) = 0,125
- .. .
jak wyciągnie Nil
z prawdopodobieństwem roztworem 0,5
Zetas nie hav e ten problem!
Można dostać dostosować te prawdopodobieństwa za pomocą frequency
zamiast oneof
jeśli chcesz:
frequency [(1,nil), (4,cons)]
tutaj trzeba będzie p(Nil) = 0.2
i p(Cons) = 0.8
ale oczywiście można dostosować to do swoich potrzeb.
Innym sposobem jest uświadomienie sobie, że List a
jest izomorficzna [a]
i ponowne wystąpienie Arbitrary
na listach:
instance Arbitrary a => Arbitrary (List a) where
arbitrary = toList <$> arbitrary
Dzięki Zeta
Biorąc pod uwagę, że' oneOf' będzie najprawdopodobniej używa tego samego prawdopodobieństwa dla wszystkich elementów na liście, jest tylko 50% szansy na uzyskanie niepustej listy, tylko 25% do uzyskania listy z jednym elementem, 12,5% do uzyskania listy z dwoma elementami, a więc na. Jeśli chcesz tego rodzaju zachowanie (np. Wygenerować listę długości 'n' z prawdopodobieństwem' 2 ** (-n + 1) ', to w porządku, ale ogólnie rzecz biorąc, doprowadzi to do krótkich list. – Zeta
tak, to prawda a twoje rozwiązanie jest oczywiście lepsze i już zostało zaakceptowane - czy chcesz, żebym to usunął? – Carsten
Nie, ale może znajdziesz alternatywny sposób generowania list, które są dłuższe, np.'toList :: [a] -> List a' i' arbitrary = toList <$> arbitralny', jako przykład dla typów isomorph do '[] a'. – Zeta