I have a ring type class which 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, e.g.
instance Ring Matrix where ...
instance Ring Integer where ...
instance Ring Modulo where ...
In order to test these instances, I have following quickcheck 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'm unsure how to run these testcases for all my class instances. 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 somewhat unsatisfied with this solution. I find the forAllRingsX functions a little ugly and repetetive. The reason is that my tests have a different number of parameters. Is there a better way (i.e. one with less boiler plate code) to test all instances?