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 a
和shrink :: a -> [a]
。
我有(也許是錯誤的)感覺,我不應該爲這樣一個簡單的函子定義任意實例。
如果我確實需要定義Identity的實例Arbitrary,那麼我不知道arbitrary
和shrink
應該是什麼樣子以及它們應該如何表現。
你能指導我嗎?