代码之家  ›  专栏  ›  技术社区  ›  Stephane Rolland

快速检查简单函数:是否需要定义任意实例?为什么?怎样

  •  1
  • Stephane Rolland  · 技术社区  · 9 年前

    我在用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) 
    

    不幸的是,这段代码无法编译,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);
               .... }
    

    所以我已经开始研究QuickCheck任意类型类,它需要定义 arbitrary :: Gen a shrink :: a -> [a] .

    我有一种(可能是错误的)感觉,我不需要为这样一个简单的函子定义任意实例。

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

    你能指导我吗?

    1 回复  |  直到 9 年前
        1
  •  5
  •   leftaroundabout    9 年前

    您确实需要该实例才能使用快速检查。

    但是 因为 这个函子很简单,很简单: Identity A 同构于 A 因此它也允许完全相同的 Arbitrary 例子这基本上和你的 Eq 例子

    instance (Arbitrary a) => Arbitrary (Identity a) where
        arbitrary = Identity <$> arbitrary
        shrink (Identity v) = Identity <$> shrink v
    
    推荐文章