QuickChecking简单的Functors:定义一个必要的Arbitrary实例吗?为什么?怎么样?

Ste*_*and 1 haskell functor quickcheck

我正在使用Functors和QuickCheck进行练习.

我有一个超级简单的Functor,其组成法我想快速检查.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) 
Run Code Online (Sandbox Code Playgroud)

不幸的是这段代码没有编译,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);
           .... }
Run Code Online (Sandbox Code Playgroud)

所以我开始研究QuickCheck Arbitrary类型类,它需要定义arbitrary :: Gen ashrink :: a -> [a].

我有(可能是错误的)感觉,我不需要为这样一个简单的仿函数定义Arbitrary实例.

如果我真的需要为身份定义实例Arbitrary,那么我不知道它应该是什么样子arbitrary以及shrink应该如何表现.

你能指导我吗?

lef*_*out 5

您确定需要该实例才能使用quickcheck.

但是,因为这个仿函数是如此简单,这非常简单:它本身Identity A是同构的A,所以它也允许完全相同的Arbitrary实例.它与您的Eq实例基本相同.

instance (Arbitrary a) => Arbitrary (Identity a) where
    arbitrary = Identity <$> arbitrary
    shrink (Identity v) = Identity <$> shrink v
Run Code Online (Sandbox Code Playgroud)