2013-12-14 22 views
2

我想弄清楚如何結合使用基於smallcheck屬性的測試庫和美味。SmallCheck:製作類型的類型實例Serial

我碰到了一個多字段記錄類型的問題:我如何創建一個記錄類型與類型爲Serial typeclass的4字段的成員?

我認爲這將是走正常的方式:

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} 

import Test.Tasty 
import Test.Tasty.SmallCheck 
import Test.SmallCheck.Series 

data T1 = T1 { p1 :: Int, 
       p2 :: Char, 
       p3 :: [Int] 
      } deriving (Show, Eq) 

instance (Monad m) => Serial m T1 where 
    series = cons3 T1 

main :: IO() 
main = defaultMain tests 

tests :: TestTree 
tests = testGroup "Tests" [scProps] 

scProps = testGroup "(checked by SmallCheck)" 
    [ testProperty "Test1" prop_test1 
    ] 

prop_test1 x y = x == y 
       where types = (x :: T1, y :: T1) 

這個工作,當然,「測試1」失敗。但是,這種方法對於超過4個字段的記錄類型不起作用,因爲consN函數僅定義爲最多需要4個參數。這裏是link到模塊Test.SmallCheck.Series的功能聲明。

類似:

data T1 = T1 { p1 :: Int, 
       p2 :: Char, 
       p3 :: Int, 
       p4 :: Int, 
       p5 :: [Int] 
      } deriving (Show, Eq) 

是什麼將它添加到Serial的方式嗎?我試着使用泛型這樣的:

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} 
{-# LANGUAGE DeriveGeneriC#-} 

import Test.Tasty 
import Test.Tasty.SmallCheck 
import Test.SmallCheck.Series 
import GHC.Generics 

data T1 = T1 { p1 :: Int, 
       p2 :: Char, 
       p3 :: [Int] 
      } deriving (Show, Generic) 

instance Serial m a => Serial m T1 

但GHC拒絕與以下消息接受上面的例子:

Variable occurs more often in a constraint than in the instance head 
    in the constraint: Serial m a 
    (Use -XUndecidableInstances to permit this) 
    In the instance declaration for `Serial m T1' 

許多在此先感謝!

jules

+0

對於你的«可選問題»,請創建一個新的問題。 –

+0

嗨羅馬人,非常感謝您的回答,並將如此多的想法和精力投入圖書館 - 我剛開始採摘它,但它似乎是一個偉大的工具!我提出了可選的問題[這裏](http://stackoverflow.com/questions/20582795/haskell-smallcheck-how-to-control-the-depth-parameter)。 – jules

+1

此信息現在包含在[documentation](http://hackage.haskell.org/package/smallcheck-1.1.1/docs/Test-SmallCheck-Series.html#g:2)中。 –

回答

3

以下是例如cons3在SmallCheck定義:

cons3 :: (Serial m a, Serial m b, Serial m c) => 
     (a->b->c->d) -> Series m d 
cons3 f = decDepth $ 
    f <$> series 
    <~> series 
    <~> series 

因此,通過類比,這裏是你如何定義實例爲你的類型與字段的任何數量的 :

instance Monad m => Serial m T1 where 
    series = decDepth $ 
    T1 <$> series <~> series <~> series <~> series <~> series 

(每series上述定義對應於一個字段的數據爲 結構)。

關於你的泛型代碼,它應該是這樣的:

instance Monad m => Serial m T1 

這裏沒有a,使您的約束是多餘的(而且實際上導致的問題)。