QuickChecking simple Functors:是否需要定义一个 Arbitrary 实例?为什么 ?如何?
QuickChecking simple Functors: Is defining an Arbitrary instance necessary ? Why ? How?
我正在使用 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类型类,它需要定义arbitrary :: Gen a
和shrink :: a -> [a]
。
我有(也许是错误的)感觉,我不需要为这样一个简单的函子定义 Arbitrary 实例。
如果我真的需要定义实例 Arbitrary for Identity,那么我不知道 arbitrary
和 shrink
应该是什么样子以及它们应该如何表现。
你能指导我吗?
您确实需要该实例才能使用 quickcheck。
但是,因为这个仿函数非常简单,所以非常简单:Identity A
与 A
本身同构,所以它也允许完全相同Arbitrary
实例。这与您的 Eq
实例基本相同。
instance (Arbitrary a) => Arbitrary (Identity a) where
arbitrary = Identity <$> arbitrary
shrink (Identity v) = Identity <$> shrink v
我正在使用 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类型类,它需要定义arbitrary :: Gen a
和shrink :: a -> [a]
。
我有(也许是错误的)感觉,我不需要为这样一个简单的函子定义 Arbitrary 实例。
如果我真的需要定义实例 Arbitrary for Identity,那么我不知道 arbitrary
和 shrink
应该是什么样子以及它们应该如何表现。
你能指导我吗?
您确实需要该实例才能使用 quickcheck。
但是,因为这个仿函数非常简单,所以非常简单:Identity A
与 A
本身同构,所以它也允许完全相同Arbitrary
实例。这与您的 Eq
实例基本相同。
instance (Arbitrary a) => Arbitrary (Identity a) where
arbitrary = Identity <$> arbitrary
shrink (Identity v) = Identity <$> shrink v