如何为包装函数的类型编写一个任意实例?

时间:2017-05-23 10:21:26

标签: haskell quickcheck

我有这种包装功能的类型

newtype Transaction d e r = Transaction (d -> Either e (d,r))

...我想对它的Functor& amp;进行快速检查。应用程序实例,但编译器抱怨它没有任意实例。

我试图这样做,但我一直坚持生成随机函数。

谢谢!

== UPDATE ==

quickcheck属性定义如下

type IdProperty f a = f a -> Bool
functorIdProp :: (Functor f, Eq (f a)) => IdProperty f a
functorIdProp x = (fmap id x) == id x

type CompositionProperty f a b c = f a -> Fun a b -> Fun b c -> Bool
functorCompProp :: (Functor f, Eq (f c)) => CompositionProperty f a b c
functorCompProp x (apply -> f) (apply -> g) = (fmap (g . f) x) == (fmap g . fmap f $ x)

instance (Arbitrary ((->) d  (Either e (d, a)))) => Arbitrary (DbTr d e a) where
    arbitrary = do
      f <- ...???
      return $ Transaction f

......测试看起来像这样:

spec = do
  describe "Functor properties for (Transaction Int String)" $ do
    it "IdProperty (Transaction Int String) Int" $ do
      property (functorIdProp :: IdProperty (Transaction Int String) Int)

    it "CompositionProperty (Transaction Int String) Int String Float" $ do
      property (functorCompProp :: CompositionProperty (Transaction Int String) Int String Float)

1 个答案:

答案 0 :(得分:3)

您应该使用Test.QuickCheck.Function包装器来测试功能。如果您只需要为Arbitrary类型测试类型类定律,那么对于CoArbitrary TransactionTransaction个实例似乎毫无意义(但如果您真的需要它,你可以找到my answer to this question)。

要测试法律,您可以按照以下方式编写属性:

{-# LANGUAGE DeriveFunctor #-}

import Test.QuickCheck
import Test.QuickCheck.Function

newtype Transaction d e r = Transaction (d -> Either e (d,r))
  deriving (Functor)

-- fmap id ≡ id
prop_transactionFunctorId :: Int
                          -> Fun Int (Either Bool (Int,String)) 
                          -> Bool
prop_transactionFunctorId d (Fun _ f) = let t              = Transaction f
                                            Transaction f' = fmap id t
                                        in f' d == f d

嗯,这可能看起来不像你想要的那么漂亮和漂亮。但这是测试任意函数的好方法。例如,我们可以将最后一行in f' d == f d替换为in f' d == f 1,以查看失败后如何失败:

ghci> quickCheck prop_transactionFunctorId 
*** Failed! Falsifiable (after 2 tests and 4 shrinks):    
0
{0->Left False, _->Right (0,"")}