Testing class types with Quickcheck, variable number of parameters

I have a call type class that looks like this:

class Ring a where
  addId  :: a
  addInverse :: a -> a
  mulId  :: a
  add :: a -> a -> a
  mul :: a -> a -> a

For this class, I have several instances, for example

instance Ring Matrix where ...
instance Ring Integer where ...
instance Ring Modulo where ...

To test these instances, I have the following validation tests:

prop_AddId :: (Ring a, Eq a, Arbitrary a) => a -> Bool
prop_AddInv :: (Ring a, Eq a, Arbitrary a) => a -> Bool
prop_MulId :: (Ring a, Eq a, Arbitrary a) => a -> Bool
prop_AddCommutative :: (Ring a, Eq a, Arbitrary a) => a -> a -> Bool
prop_AddAssociative :: (Ring a, Eq a, Arbitrary a) => a -> a -> a -> Bool
prop_MulAssociative :: (Ring a, Eq a, Arbitrary a) => a -> a -> a -> Bool
prop_Distributive :: (Ring a, Eq a, Arbitrary a) => a -> a -> a -> Bool

I am not sure how to run these test files for all instances of my class. I found a solution here which leads to the following:

forallRings :: (forall a. (Ring a, Arbitrary a, Eq a) => a -> Bool) -> [IO ()]
forallRings x =
    [ quickCheck (x :: Matrix -> Bool)
    , quickCheck (x :: Integer -> Bool)
    , quickCheck (x :: Modulo -> Bool)
    ]
forallRings2 :: (forall a. (Ring a, Arbitrary a, Eq a) => a -> a -> Bool) -> [IO ()]
forallRings2 x =
    [ quickCheck (x :: Matrix -> Matrix -> Bool)
    , quickCheck (x :: Integer -> Integer -> Bool)
    , quickCheck (x :: Modulo -> Modulo -> Bool)
    ]
forallRings3 :: (forall a. (Ring a, Arbitrary a, Eq a) => a -> a -> a -> Bool) -> [IO ()]
forallRings3 x =
    [ quickCheck (x :: Matrix -> Matrix -> Matrix -> Bool)
    , quickCheck (x :: Integer -> Integer -> Integer -> Bool)
    , quickCheck (x :: Modulo -> Modulo -> Modulo -> Bool)
    ]

ringTests :: IO ()
ringTests = sequence_ $
            forallRings propAddId
            ++ forallRings prop_AddInv
            ++ forallRings prop_MulId
            ++ forallRings2 prop_AddCommutative
            ++ forallRings3 prop_AddAssociative
            ++ forallRings3 prop_MulAssociative
            ++ forallRings3 prop_Distributive

I am a bit dissatisfied with this decision. I find the forAllRingsX functions are a bit ugly and repetitive. The reason is because my tests have a different number of parameters. Is there a better way (i.e., One with a smaller boiler plate code) to check all instances?

+4
1

, typeclass - . - Ring, ringTests :: (Eq a, Arbitrary a) => proxy a -> IO Result. - , : ringTests (Proxy :: Proxy Matrix).

ringTests , ; ScopedTypeVariables, .

, . instance RingTests Matrix where .., .

+3

All Articles