2011-10-08 6 views
12
-- 3 (find k"th element of a list) 
element_at xs x = xs !! x 
prop_3a xs x = (x < length xs && x >= 0) ==> element_at xs (x::Int) == (xs !! x::Int) 

prop_3aをQuickCheckで実行すると、十分長いリストが生成されないため、QuickCheckが実行されます。HaskellのQuickCheckで特定の長さのリストを生成する

ランダムな整数より長い長さのリストを生成するジェネレータを作成するにはどうすればよいですか?

答えて

10

他の方法はどうですか?最初に、QuickCheckにリストを選択させてから、私たちが許可するインデックスを制限します。これは動作し、テストケースを捨てません。ここで

prop_3a (NonEmpty xs) = forAll (choose (0, length xs - 1)) $ \i -> 
    element_at xs i == (xs !! i :: Int) 

は、私が指定した範囲から要素をピックアップchooseを使用して、この場合には、インデックスのための特定の発電機を使用するforAllを使用して、私はまた、我々はインデックスにしようとしないことを確実にするためにthe NonEmptyList typeを使用します空のリストに入れます。

+0

これは完全に機能するようですが、理解するためにコードをさらに検討する必要があります。 :) –

+0

グーグル以外、どのようなパッケージがNonEmptyを提供しているかを知るにはどうすればいいですか? –

+1

@JoeVanDyk:[QuickCheckから](http://hackage.haskell.org/packages/archive/QuickCheck/2.4.1.1/doc/html/Test-QuickCheck.html#t:NonEmptyList)です。 – hammar

3

これは動作します:

import Test.QuickCheck 

element_at  :: [a] -> Int -> a 
element_at xs i = xs !! i 

prop_3a  :: [Int] -> Int -> Property 
prop_3a xs i = (i >= 0) ==> (length xs > i) ==> element_at xs i == xs !! i 

しかし、これに伴う問題は、サンプル値の多くが破棄されていることです。 Positiveのようなものを使用して、索引が有効であることを確認することができます。

さらに複雑な場合は、より多くのnewtypeラッパーを使用して十分な長さの値を生成したり(おそらくsizedを使用するか、リストとインデックスを一緒に生成します)、リストを生成し、リストの長さに応じて)。

9

ハマールの答えは問題に完全に適しています。しかし、質問された正確な質問に答えるために、私はちょっと調べることができませんでした。 forAllを使用しましょう。

prop_bang x = x >= 0 ==> forAll (listLongerThan x) $ \xs -> 
    element_at xs x == xs !! x 

ここで関数listLongerThan :: Int -> Gen [Int]が必要です。長さxをとり、xより大きい長さのリストを生成するジェネレータを生成します。

listLongerThan :: Int -> Gen [Int] 
listLongerThan x = replicateM (x+1) arbitrary 

わかりやすく、GenのMonadインスタンスを利用しています。 quickCheck prop_bangを実行すると、不合理に長いリストのテストが始まるので、かなり長い時間がかかり始めることに気付くでしょう。リストの長さを制限して、少し速くしましょう。また、今すぐlistLongerThanは、ちょうどx+1の長さのリストを生成します。さんが再びあなたはそれが正しいものを生成していることを確認するGHCiの中sample smallNumberまたはsample (listLongerThan 3)を使用することができ将軍

prop_bang = 
    forAll smallNumber $ \x -> 
    forAll (listLongerThan x) $ \xs -> 
    element_at xs x == xs !! x 

smallNumber :: Gen Int 
smallNumber = fmap ((`mod` 100) . abs) arbitrary 

listLongerThan :: Int -> Gen [Int] 
listLongerThan x = do 
    y <- fmap (+1) smallNumber -- y > 0 
    replicateM (x+y) arbitrary 

のモナドのインスタンスを利用し、少しそれをミックスしてみましょう。

+2

replicateMの代わりに、私はむしろ 'vector'関数を使うでしょう –

関連する問題