2016-03-17 20 views
5

これは長さ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)))) 

答えて

6

もう一つの方法は、List a[a]に同型であることを認識し、リストのArbitraryインスタンスを再利用することです。意味は、インスタンスまでですが、それは、生成された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) 

比較のために、ここで[]さんarbitrary instanceです: `oneOf`がすることを考えると

instance Arbitrary a => Arbitrary [a] where 
    arbitrary = sized $ \n -> 
    do k <- choose (0,n) 
     sequence [ arbitrary | _ <- [1..k] ] 
4

あなたは空のリストのどちらかを選ぶか、再帰的に長いリストを生成するためにoneofを使用することができます。

λ> generate (arbitrary :: Gen (List Int)) 
Nil 
λ> generate (arbitrary :: Gen (List Int)) 
Cons 4 (Cons 26 Nil) 
λ> generate (arbitrary :: Gen (List Int)) 
Nil 

発言

として:ここ

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 

はいくつかのテストですゼータはこれを指摘しました。あなたには明らかな欠陥があります。病気おそらく非常に短いリストを生成:

  • P(無記号)= 0.5
  • P((_ Cons無記号)= 0.25
  • P((_ Cons _ Cons無記号)= 0.125
  • ..それは0.5

    ゼータソリューションは肝炎しない確率でNilを描きますよう。

eこの問題!

あなたが好きなら代わりにoneoffrequencyを使用して、これらの確率を適応取得することができます。

ここ
frequency [(1,nil), (4,cons)] 

あなたはp(Nil) = 0.2p(Cons) = 0.8を持っていますが、もちろん、あなたの好みに合わせて、これを適応させることができます。 sized

instance Arbitrary a => Arbitrary (List a) where 
    arbitrary = toList <$> arbitrary 

おかげゼタ

+1

ほとんどの場合、リスト内のすべての要素に同じ確率を使用します。空でないリストを取得する確率は50%、1つの要素でリストを取得するには25%、2つの要素でリストを取得するには12.5%に。あなたがそのような振る舞いを望むなら(例えば '' 2 **(-n + 1) 'という確率で長さ 'n'のリストを生成する)、それは問題ありませんが、一般的に、これは短いリストにつながります。 – Zeta

+0

はいあなたの解決策は明らかに優れており、すでに受け入れられているので、これを削除したいのですか? – Carsten

+0

Nah、しかしもっと長いリストを生成する代替手段を見つけることができます。'[] a'と同型である型の例として、' toList :: [a] - > List a'と 'arbitrary = toList <$> arbitrary'を例に挙げます。 – Zeta

関連する問題