簡體   English   中英

使用類型同義詞時如何約束QuickCheck?

[英]How do I constrain QuickCheck when using type synonyms?

我正在使用QuickCheck在我的代碼上運行任意測試用例。 但是,在我的代碼的一部分中,我具有類型同義詞:

type Vector = [Double]

我也有一些函數可以接受許多Vector作為輸入。 但是,所有這些功能都要求Vector的長度相同。

有沒有一種方法可以限制QuickCheck ,使其僅生成長度為n的列表?

一個簡單的解決方案是不具有任意實例,而要做類似的事情

import Test.QuickCheck
import Control.Monad

prop_vec :: Int -> Gen [Double]
prop_vec = flip replicateM arbitrary . abs


prop_addComm :: Int -> Gen Bool
prop_addComm i  = do
  v <- prop_vec i
  u <- prop_vec i
  return $ u + v = v + u --assuming you'd added a Num instance for your vectors

從來沒有類型類,所以您得到的幫助失敗較少,但是更容易上手。

您可以使用==>表示法設置約束。

一個例子是:

prop_test xs = minimum xs == (head $ sort xs)

失敗:

*** Failed! Exception: 'Prelude.minimum: empty list' (after 1 test):
[]

現在有一個約束:

prop_test xs = not (null xs) ==> minimum xs == (head $ sort xs)

有用:

*Main> quickCheck prop_test
+++ OK, passed 100 tests.

在您的情況下:

prop_test xs ys = length xs == length ys ==> undefined -- whatever you want

另一個明顯的解決方案是生成一個元組列表並將其解壓縮。 例如,在ghci中:

> let allSameLength (xs:xss) = all (==length xs) (map length xss)
> quickCheck (\xys -> let (xs, ys) = unzip xys in allSameLength [xs, ys])
+++ OK, passed 100 tests.
> :{
| quickCheck (\wxyzs -> let
|   (wxs, yzs) = unzip wxyzs
|   (ws, xs) = unzip wxs
|   (ys, zs) = unzip yzs
|   in allSameLength [ws, xs, ys, zs])
| :}
+++ OK, passed 100 tests.

這是一種可能性。 我們將為可以構建與大小相關的隨機值的類型定義一個新類。 然后,您可以創建類型級別的列表或樹或其他任何內容,並為這些聲明一次Arbitrary實例。

import Control.Monad
import Test.QuickCheck

class SizedArbitrary a where
    sizedArbitrary :: Int -> Gen a

instance Arbitrary a => SizedArbitrary [a] where
    sizedArbitrary n = replicateM n arbitrary

data Branch a b = a :+ b deriving (Eq, Ord, Show, Read)
instance (SizedArbitrary a, SizedArbitrary b) => SizedArbitrary (Branch a b) where
    sizedArbitrary n = liftM2 (:+) (sizedArbitrary n) (sizedArbitrary n)

instance (SizedArbitrary a, SizedArbitrary b) => Arbitrary (Branch a b) where
    arbitrary = arbitrarySizedIntegral >>= sizedArbitrary . abs

然后我們可以將其加載到ghci中,並檢查其是否有效:

*Main> let allSameLength (xs:xss) = all (==length xs) (map length xss)
*Main> quickCheck (\(xs :+ ys) -> allSameLength [xs, ys])
+++ OK, passed 100 tests.
*Main> quickCheck (\(ws :+ xs :+ ys :+ zs) -> allSameLength [ws, xs, ys, zs])
+++ OK, passed 100 tests.

暫無
暫無

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

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