2016-02-26 38 views
1

我正在用Functors和QuickCheck做運動。QuickChecking simple Functors:是否需要定義任意實例?爲什麼?怎麼樣?

我有一個超級簡單的函數,其組成法我希望quickCheck。 該Functor只是一個Identity a。 這是我的代碼至今:

import Data.Functor 
import Test.QuickCheck 

newtype Identity a = Identity a 

instance (Eq a) => Eq (Identity a) where 
    (==) (Identity x) (Identity y) = x == y 
    (/=) (Identity x) (Identity y) = x /= y 

instance Functor Identity where 
    fmap f (Identity x) = Identity (f x) 

propertyFunctorCompose ::(Eq (f c), Functor f) => (a -> b) -> (b -> c) -> f a -> Bool 
propertyFunctorCompose f g fr = (fmap (g . f) fr) == (fmap g . fmap f) fr 

main = do 
    quickCheck $ \x -> propertyFunctorCompose (+1) (*2) (x :: Identity Int) 

遺憾的是這段代碼不能編譯,GHC與此編譯錯誤抱怨:

functor_exercises.hs:43:5: 
    No instance for (Arbitrary (Identity Int)) 
     arising from a use of `quickCheck' 
    Possible fix: 
     add an instance declaration for (Arbitrary (Identity Int)) 
    In the expression: quickCheck 
    In a stmt of a 'do' block: 
     quickCheck $ \ x -> propertyFunctorId (x :: Identity Int) 
    In the expression: 
     do { quickCheck $ \ x -> propertyFunctorId (x :: [Int]); 
      quickCheck 
      $ \ x -> propertyFunctorCompose (+ 1) (* 2) (x :: [Int]); 
      quickCheck (propertyFunctorCompose' :: IntFC); 
      quickCheck $ \ x -> propertyFunctorId (x :: Identity Int); 
      .... } 

所以我已經開始看快速檢查任意類型類,它需要定義arbitrary :: Gen ashrink :: a -> [a]

我有(也許是錯誤的)感覺,我不應該爲這樣一個簡單的函子定義任意實例。

如果我確實需要定義Identity的實例Arbitrary,那麼我不知道arbitraryshrink應該是什麼樣子以及它們應該如何表現。

你能指導我嗎?

回答

5

您確定需要該實例才能使用quickcheck。

但是,由於函子就是這麼簡單,這是相當簡單:Identity A同構於A本身,因此它也允許完全相同的Arbitrary實例。這與您的Eq實例基本相同。

instance (Arbitrary a) => Arbitrary (Identity a) where 
    arbitrary = Identity <$> arbitrary 
    shrink (Identity v) = Identity <$> shrink v 
相關問題