2011-04-13 47 views
8

我有一些包含QuickCheck測試用例的舊Haskell代碼。較新版本的QuickCheck(我剛剛升級到2.4.0.1)包含Arbitrary Word8等的類型實例。這些在Test.QuickCheck.Arbitrary較早的2.0.x版本中不存在。如何覆蓋程序包代碼提供的Haskell類型類實例?

雖然有用在一般意義上,包提供的Arbitrary Word8發生器是不是我想用我的測試套件:

instance Arbitrary Word8 where 
    arbitrary = frequency [(2, oneof [return ctrlFrameDelim, return ctrlEscape, return ctrlXon, return ctrlXoff]), 
         (8, choose (0, 255))] 

上面的代碼導致重複實例聲明的錯誤在編譯時。我可以把這段代碼拿出來,並通過默認的發生器獲取,但我想知道解決這個問題的正確方法。

我考慮過的一個可能的解決方案是使用newtype來別名Word8。這將導致整個源代碼的很多變化,所以我希望有一個更清晰的方法。

編輯:由於在下面的評論中提到,接受的答案很乾淨,容易實現:

newtype EncodedByte = EncodedByte Word8 

instance Arbitrary EncodedByte where 
    arbitrary = liftM EncodedByte $ frequency [(2, elements [ctrlFrameDelim, ctrlEscape, ctrlXon, ctrlXoff]), 
              (8, choose (0, 255))] 

回答

7

一個newtype別名是這裏的標準解決方案。在大多數情況下,這可能不包括你的,這不是什麼大問題,因爲newtype包裝器只需要出現在你使用任意類型類型的地方。例如,你可能有一些頂級:

x <- arbitrary 

,而是你必須

newtype SomeNewType = SNT Word8 
instance Arbitrary SomeNewType where ... 
.... 
    SNT x <- arbitrary 

什麼你可能想不存在,作爲一個GHC擴展 - 你要明確的導入和導出的實例。如果你有明確的情況下進口,這將使:

import Test.QuickCheck hiding (Arbitrary(Word8)) 

但破壞很多的,目前的工作方式實例的隱含進口代碼:

import Test.QuickCheck (quickCheck) -- note the implicit import of Arbitrary(..) 
+4

很多人似乎認爲這個解決方案難看。但是如果你允許「數據類型」的含義超過價值的表示,我覺得這是完全合理的。例如,你不只是在談論'Word8',你正在談論'ControlCode'或類似的東西。 – luqui 2011-04-13 01:42:09

+0

工作很好。事實證明,別名不需要任何級聯更改。我只需要爲「選擇」提供一個額外的「實例Random SomeNewType」聲明。 – 2011-04-13 03:23:36