I will try to provide some intuition, simplifying things a bit.
ps :: C a => [P a] is a contract between the implementation of ps and its user. According to it,
- the user can choose any
a
- the user must prove that
C a holds
- then, the implementation must provide a value of type
[P a].
For instance, the user could choose a ~ D1. The instance is then used to prove C D1, so the contract is satisfied. The implementation must then, in this case, provide a value of type [P D1].
Your implementation is [mkP_D1 1, mkP_D2 2]. For the above case, the value mkP_D1 1 follows the contract since it's a P D1. However, mkP_D2 2 is not a P D1 (but is a P D2), violating the contract.
Since there is an instance where the user fulfills the contract but the implementation does not, the code is rejected by the type checker.
More pedantically, the issue here is that a is chosen by the user, not the implementation. If the implementation tries to choose some specific type a, there is a chance the user will pick something else, and the compiler will rightfully complain in that case.
Why is it that qs works fine?
qs :: Num a => [a]
qs = [1, 2]
Here the user chooses a, but qs does not. Indeed, 1 is of any (numeric) type a, and so is 2.
Compare this with ps, which tries to choose a. Incidentally, ps not only tries to chooses a to be D1 (which would already trigger the "rigid variable" error), but also tries to choose a to be D2 (which makes the situation even worse).
A possible working implementation is to add a method to the class:
class C a where
mkP :: Int -> P a
instance C D1 where
mkP = P
instance C D2 where
mkP = P
ps :: C a => [P a]
ps = [mkP 1, mkP 2]
Note that this is only an example. You could use P directly and avoid introducing the new method in the class.
qsboth elements of the list are of the same typea, while inpsthey're of different typesP D1andP D2. The equivalent non-working version ofqswould beqs = [ (1 :: Int), (2 :: Double) ]- Fyodor Soikinpsthe constraint is being satisfied, so why does the compiler complain? - Lo HaBuyshanps :: [(forall a. C a => P a)], that should work. - Fyodor SoikinRankNTypes, but then complained * Illegal polymorphic type:forall a. C a => P aGHC doesn't yet support impredicative polymorphism * In the type signature:ps :: [(forall a. C a => P a)]- Lo HaBuyshan