Lets say I've got the class:
class C a b t where
f :: (a, b) -> (t a, t b)
Now with this definition, I can define instances for say:
(a,b) -> (Maybe a, Maybe b)
(a,b) -> ([a], [b])
But not for (as far as I understand):
(a,b) -> (a,b)
(a,b) -> ((a, a), (b, b))
I could instead change my class definition like so:
type family T a b x
class C a b where
f :: (a, b) -> (T a b a, T a b b)
Which would allow me to do the above, but then I'd only be able to declare one f for each a and b.
Basically I want to be able to pass a type family as t in the original definition, which is implicitly resolved by the type checker if known. I don't want to just make it f :: (a, b) -> (c, d) as I want to maintain the invariant that both a and b have the same thing done to them, so swap . f is the same type as f . swap. I'm thinking I might need injective type families (from GHC 8.0) but I'm not sure. But maybe there's another way?