A type-level "implies" constraint on Constraints
I have a datatype:
data Exists c where Exists :: c a => a -> Exists c
I have an instance for it:
instance Show (Exists Show) where show (Exists a) = show a
And that's alright, as far as it goes: any Exists Show can indeed itself be shown. But I want more. I want to be able to say:
instance (c `Implies` Show) => Show (Exists c) where show (Exists a) = show a
In other words, I want to be able to say that any (Exists c) where the constraint c implies Show can be shown. For example, if Num still had a Show constraint, I wouldn't want to have to write a separate instance Show (Exists Num) to be able to show an Exists Num; I would want to be able to write a single instance (along the lines of the above) which works for both.
GHC clearly has this information: it lets me use a function of type
forall a. Eq a => a -> r as one of type
forall a. Ord a => a -> r, but not vice versa, so it knows that Ord implies Eq, but not vice versa. I've attached a file which demonstrates this and a couple of other examples.
What's not completely clear to me is what would be the appropriate way to be able to ask it about this. An Implies constraint to parallel the (~) constraint would work, but with what syntax? (Just straightforwardly call it Implies?) And what semantics -- what would be the kind of Implies? It's notable that in the above example its arguments aren't of type Constraint, but rather * -> Constraint, and for (* -> *) -> Constraint it could similarly work, and with MPTCs * -> * -> Constraint and (* -> *) -> (* -> *) -> Constraint and * -> (* -> *) -> Constraint and so on probably also make sense... but I have no idea how to formalize this, where the boundaries lie, and whether it makes any kind of sense. I can try to think harder about it if that would help, but hopefully the outlines of the situation are more immediately obvious to someone on the GHC team.
|Component||Compiler (Type checker)|