簡體   English   中英

使用Haskell的QuickCheck生成特定長度的列表

[英]Generating a lists of a specific length with Haskell's QuickCheck

-- 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運行時,它會放棄,因為它不會生成足夠長的列表。

如何編寫生成長度超過隨機整數的列表的生成器?

哈馬爾的答案完全適合這個問題。 但為了回答所提出的確切問題,我忍不住調查了一下。 讓我們一起使用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長的列表; 讓我們再混合一下,再次利用Gen的Monad實例。

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

您可以在ghci中使用sample smallNumbersample (listLongerThan 3)來確保它生成正確的內容。

走另一條路怎么樣? 首先,我們讓QuickCheck選擇一個列表,然后我們約束我們允許的索引。 這有效,並且不會丟棄任何測試用例。

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

在這里,我使用forAll為索引使用特定的生成器,在這種情況下使用choose從指定范圍中選擇一個元素,並且我還使用NonEmptyList類型來確保我們不嘗試索引到空列表。

這有效:

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 ,或者一起生成列表和索引:生成列表,然后根據長度生成索引名單)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM