Implement {-# OVERLAPPABLE #-} and {-# INCOHERENT #-} pragmas
The language extensions -XIncoherentInstances
and -XOverlappingInstances
(described in the user manual) apply to every instance declaration in the module. Internally, however, GHC records this information on a per-instance-declaration basis.
It would be much better for the programmer to be able to control these matters on a per-instance-declaration basis. Thus:
instance Show a => Show [a] where
{-# OVERLAPPABLE #-}
...
instance Show [Char] where
...
We came across the need for this when discussing the Typeable
instances. We have a generic instance like this:
instance (Typeable f, Typeable a) => Typeable (f a) where ....
but also want
instance KnownNat n => Typeable (n :: Nat) where ...
If we seek (Typeable (x::Nat))
, we should pick the second instance even though in principle you might imagine that x
might be instantiated to (f a)
, for some f
and a
. But we know that there are no type constructors f
of kind blah -> Nat
, so this can never happen and it's safe to pick the second instance. So a local {-# INCOHERENT #-}
pragma for this particular instance declaration would be very useful to express this fact.
instance KnownNat n => Typeable (n :: Nat) where
{-# INCOHERENT #-}
...
Quite apart from this special case, it's plain better to have per-instance control
- Rather than a remote per-module flag, the pragma draws attention that this particular instance is incoherent, overlappable or whatever.
- The current situation almost certainly means that more instances are marked overlapping than are really necessary.
I have some design questions.
- Where should the pragma appear, syntactically?
instance {-# OVERLAPPABLE #-} Show a => Show [a] where ...
or
instance Show a => Show [a] {-# OVERLAPPABLE #-} where ...
or
instance Show a => Show [a] where
{-# OVERLAPPABLE #-}
Remember that SPECIALISE INSTANCE
pragmas appear in the third of the above positions, so I mildly favour that.
- The user manual (link above) allows overlap if either instance is compiled with
-XOverlappingInstances
(see the rules towards the end of 7.6.3.5). It would be more explicit to have two pragmas, one to say "I can be overlapped" and one to say "I can overlap something else". The rule would then be that "either IX is marked{-# OVERLAPPABLE #-}
or IY is marked{-# OVERLAPPING #-}
.