Note [GND and associated type families]
It's possible to use GeneralizedNewtypeDeriving (GND) to derive instances for
classes with associated type families. A general recipe is:
class C x y z where
type T y z x
op :: x -> [y] -> z
newtype N a = MkN <rep-type> deriving( C )
=====>
instance C x y <rep-type> => C x y (N a) where
type T y (N a) x = T y <rep-type> x
op = coerce (op :: x -> [y] -> <rep-type>)
However, we must watch out for three things:
(a) The class must not contain any data families. If it did, we'd have to
generate a fresh data constructor name for the derived data family
instance, and it's not clear how to do this.
(b) Each associated type family's type variables must mention the last type
variable of the class. As an example, you wouldn't be able to use GND to
derive an instance of this class:
class C a b where
type T a
But you would be able to derive an instance of this class:
class C a b where
type T b
The difference is that in the latter T mentions the last parameter of C
(i.e., it mentions b), but the former T does not. If you tried, e.g.,
newtype Foo x = Foo x deriving (C a)
with the former definition of C, you'd end up with something like this:
instance C a (Foo x) where
type T a = T ???
This T family instance doesn't mention the newtype (or its representation
type) at all, so we disallow such constructions with GND.
(c) UndecidableInstances might need to be enabled. Here's a case where it is
most definitely necessary:
class C a where
type T a
newtype Loop = Loop MkLoop deriving C
=====>
instance C Loop where
type T Loop = T Loop
Obviously, T Loop would send the typechecker into a loop. Unfortunately,
you might even need UndecidableInstances even in cases where the
typechecker would be guaranteed to terminate. For example:
instance C Int where
type C Int = Int
newtype MyInt = MyInt Int deriving C
=====>
instance C MyInt where
type T MyInt = T Int
GHC's termination checker isn't sophisticated enough to conclude that the
definition of T MyInt terminates, so UndecidableInstances is required.
(d) For the time being, we do not allow the last type variable of the class to
appear in a /kind/ of an associated type family definition. For instance:
class C a where
type T1 a -- OK
type T2 (x :: a) -- Illegal: a appears in the kind of x
type T3 y :: a -- Illegal: a appears in the kind of (T3 y)
The reason we disallow this is because our current approach to deriving
associated type family instances—i.e., by unwrapping the newtype's type
constructor as shown above—is ill-equipped to handle the scenario when
the last type variable appears as an implicit argument. In the worst case,
allowing the last variable to appear in a kind can result in improper Core
being generated (see #14728).
There is hope for this feature being added some day, as one could
conceivably take a newtype axiom (which witnesses a coercion between a
newtype and its representation type) at lift that through each associated
type at the Core level. See #14728, comment:3 for a sketch of how this
might work. Until then, we disallow this featurette wholesale.
The same criteria apply to DerivingVia.
************************************************************************
* *
Bindings for the various classes
* *
************************************************************************
After all the trouble to figure out the required context for the
derived instance declarations, all that's left is to chug along to
produce them. They will then be shoved into @tcInstDecls2@, which
will do all its usual business.
There are lots of possibilities for code to generate. Here are
various general remarks.
PRINCIPLES:
\begin{itemize}
\item
We want derived instances of @Eq@ and @Ord@ (both v common) to be
``you-couldn't-do-better-by-hand'' efficient.
\item
Deriving @Show@---also pretty common--- should also be reasonable good code.
\item
Deriving for the other classes isn't that common or that big a deal.
\end{itemize}
PRAGMATICS:
\begin{itemize}
\item
Deriving @Ord@ is done mostly with the 1.3 @compare@ method.
\item
Deriving @Eq@ also uses @compare@, if we're deriving @Ord@, too.
\item
We {\em normally} generate code only for the non-defaulted methods;
there are some exceptions for @Eq@ and (especially) @Ord@...
\item
Sometimes we use a @_con2tag_<tycon>@ function, which returns a data
constructor's numeric (@Int#@) tag. These are generated by
@gen_tag_n_con_binds@, and the heuristic for deciding if one of
these is around is given by @hasCon2TagFun@.
The examples under the different sections below will make this
clearer.
\item
Much less often (really just for deriving @Ix@), we use a
@_tag2con_<tycon>@ function. See the examples.
\item
We use the renamer!!! Reason: we're supposed to be
producing @LHsBinds Name@ for the methods, but that means
producing correctly-uniquified code on the fly. This is entirely
possible (the @TcM@ monad has a @UniqueSupply@), but it is painful.
So, instead, we produce @MonoBinds RdrName@ then heave 'em through
the renamer. What a great hack!
\end{itemize} References 0
This Note does not link to any other.
Referenced by 8
- GHC.Tc.Deriv call site ×5
- GHC.Tc.Deriv.Generate call site ×2
- Newtype-deriving instances GHC.Tc.Deriv.Generate