Suppose we have a function f :: (T a) => a -> a -> a -> in a typeclass T, typeclass which has instances in numerous types.
Suppose we want this function to be commutative regardless of its implementation for a given type, i. e.
∀ a, b ∈ X: (T X, Eq X) => ∃ f X -> X -> X, f a b == f b a
If I were to verify commutativity for a more concrete case, let`s say (+) and Int, I could write something like this:
import Test.Quickcheck (quickCheck)
commutativityProperty :: Eq a => (a -> a -> a) -> a -> a -> Bool
commutativityProperty f a b = f a b == f b a
main :: IO ()
main = do
quickCheck (commutativityProperty (+) :: Int -> Int -> Bool)
quickCheck does not work with ambiguous type variables, so I could not write something like this:
quickCheck (commutativityProperty (+) :: (Num a, Eq a) => a -> a -> Bool)
Or, for the more general case:
quickCheck (commutativityProperty f :: (T a, Eq a) => a -> a -> Bool)
The Question is:
In a similar context, where I know this function must hold commutativity regardless of implementation for a specific type, how can I verify that this is indeed true without having to write a line of quickCheck for every type that implements f and have to maintain that code (i.e. every time a new type with an instance of T is created, I would have to come back and write a new line for that specific type)?