I'm looking for a way to combine two (or more) constraints such that Combine c1 c2 a implies both c1 a and c2 a, and vice versa. This could be useful when constraints are used as input:
data HList constraint where
Empty :: HList constraint
(:*:) :: constraint a => a -> HList constraint -> HList constraint
Where show and negate could be applied to elements of an hlist typed HList (Combine Show Num).
Having these requirements, type Combine c1 c2 a = (c1 a, c2 a) won't do as type synonyms must be saturated. I as well tried declaring Combine as a class but couldn't imply that (Combine c1 c2 a) => c1 a or c2 a:
class (c1 a, c2 a) => Combine c1 c2 a
instance (c1 a, c2 a) => Combine c1 c2 a
instance Combine c1 c2 a => c1 a -- error: Illegal head of an instance declaration
instance Combine c1 c2 a => c2 a -- error: Illegal head of an instance declaration
I wonder if this is truly possible, or else what are the good workarounds.
The fact that
Combine c1 c2 aimpliesc1 aandc2 ais already contained in the declarationThat's just how superclasses work! This is a feature you've definitely seen before.
So everything you want
Combineto do is accomplished by writing simplyE.g. the following typechecks