... | ... | @@ -76,45 +76,49 @@ This demonstrates why part 3 is important: with multiple `deriving` clauses, one |
|
|
|
|
|
With `-XDerivingStrategies` in the picture, we can now state how GHC figures out which deriving strategy to use for a particular derived instance:
|
|
|
|
|
|
1. Look for a deriving strategy. If one is present, use that.
|
|
|
1. Look for a deriving strategy. If one is present, use that. This will throw an error if you try to do something silly, like using the `newtype` strategy on a non-newtype or the `bespoke` keyword with a typeclass that doesn't support `bespoke` instances.
|
|
|
|
|
|
1. (a) If deriving an `Eq`, `Ord`, `Ix`, or `Bounded` instance for a newtype, use the `GeneralizedNewtypeDeriving` strategy (even if the language extension isn't enabled).
|
|
|
1. If deriving a bespoke typeclass instance:
|
|
|
|
|
|
>
|
|
|
> (b) If deriving a `Read`, `Show`, `Data`, `Generic`, `Generic1`, `Typeable`, `Traversable`, or `Lift` instance for a newtype, go to step 3.
|
|
|
> (a) If deriving `Eq`, `Ord`, `Ix`, or `Bounded` for a newtype, use the `GeneralizedNewtypeDeriving` strategy (even if the language extension isn't enabled).
|
|
|
|
|
|
>
|
|
|
> (c) Otherwise, if deriving a `Functor`, `Foldable`, or `Enum` instance for a newtype, the datatype and typeclass can be successfully used with `GeneralizedNewtypeDeriving`, and `-XGeneralizedNewtypeDeriving` is enabled, derive the class using the `GeneralizedNewtypeDeriving` strategy.
|
|
|
> (b) If deriving `Functor`, `Foldable`, or `Enum`(?) for a newtype, the datatype can be successfully used with `GeneralizedNewtypeDeriving`, and `-XGeneralizedNewtypeDeriving` has been enabled, use the `GeneralizedNewtypeDeriving` strategy.
|
|
|
|
|
|
>
|
|
|
> (d) Otherwise, if deriving an instance for a newtype and both `-XGeneralizedNewtypeDeriving` and `-XDeriveAnyClass` are enabled, default to `DeriveAnyClass`, but emit a warning stating the ambiguity.
|
|
|
> (c) Otherwise, if deriving a bespoke typeclass instance, and the corresponding language extension is enabled (if necessary), use the bespoke strategy. If the language extension is not enabled, throw an error.
|
|
|
|
|
|
1. If not deriving a bespoke typeclass instance:
|
|
|
|
|
|
>
|
|
|
> (e) Otherwise, if deriving an instance for a newtype, the datatype and typeclass can be successfully used with `GeneralizedNewtypeDeriving`, and `-XGeneralizedNewtypeDeriving` is enabled, do so.
|
|
|
> (a) If deriving an instance for a newtype and both `-XGeneralizedNewtypeDeriving` and `-XDeriveAnyClass` are enabled, default to `DeriveAnyClass`, but emit a warning stating the ambiguity.
|
|
|
|
|
|
1. (a) If deriving a "standard derivable class" (e.g., `Eq`, `Ord`, `Generic`, etc.) and the corresponding language extension is enabled (if necessary), do so. If the language extension is not enabled, throw an error.
|
|
|
>
|
|
|
> (b) Otherwise, if `-XDeriveAnyClass` is enabled, use `DeriveAnyClass`.
|
|
|
|
|
|
>
|
|
|
> (b) Otherwise, if `-XDeriveAnyClass` is enabled, use that.
|
|
|
> (c) Otherwise, if deriving an instance for a newtype, the datatype and typeclass can be successfully used with `GeneralizedNewtypeDeriving`, and `-XGeneralizedNewtypeDeriving` is enabled, do so.
|
|
|
|
|
|
>
|
|
|
> (c) Otherwise, throw an error.
|
|
|
> (d) Otherwise, throw an error.
|
|
|
|
|
|
|
|
|
Step 2 is massively complicated since GHC tries to use `GeneralizedNewtypeDeriving` in certain special cases whenever it can to optimize the generated instances. In addition, the phrase "can be successfully used with `GeneralizedNewtypeDeriving`" must be invoked since it is possible for `GeneralizedNewtypeDeriving` on certain datatypes. For example, you cannot have a newtype-derived `Functor` instance for `newtype Compose f g a = Compose (f (g a))`, since the last type variable `a` cannot be eta-reduced.
|
|
|
The phrase "bespoke typeclass" refers to the classes listed [ here](http://git.haskell.org/ghc.git/blob/8fe1672a9c4229b884b8dcebb9be57efa4c1fdb8:/compiler/typecheck/TcGenDeriv.hs#l123), plus `Generic` and `Generic1`.
|
|
|
|
|
|
|
|
|
Step 2.(c) deserves some explanation. As a rule, in the absence of an explicit `anyclass` keyword, GHC will never attempt to derive a "standard derivable class" using the `DeriveAnyClass` strategy, since it is guaranteed that doing so would not produce the instance you'd want. This also applies when derivable a standard derivable class for a newtype when both `-XGeneralizedNewtypeDeriving` and `-XDeriveAnyClass` are enabled, which is why we need the special case of 2.(c) to come before 2.(d) so that `-XDeriveAnyClass` doesn't kick in when it shouldn't. This fixes the problem originally reported in Trac [\#10598](https://gitlab.haskell.org//ghc/ghc/issues/10598).
|
|
|
Step 2 is fairly intricate since GHC tries to use `GeneralizedNewtypeDeriving` in certain special cases whenever it can to optimize the generated instances. In addition, the phrase "can be successfully used with `GeneralizedNewtypeDeriving`" must be invoked since it is possible for `GeneralizedNewtypeDeriving` to fail for certain datatypes. For example, you cannot have a newtype-derived `Functor` instance for `newtype Compose f g a = Compose (f (g a))`, since the last type variable `a` cannot be eta-reduced.
|
|
|
|
|
|
|
|
|
The phrase "standard derivable class" is a bit sloppy since not all such classes are in a Haskell standard—in fact, many require turning on language extensions to be "standard" derived! Due to a lack of a better phrase, and since the phrase itself appears in GHC error messages, it's used here.
|
|
|
Step 2.(b) deserves some explanation. As a rule, in the absence of an explicit `anyclass` keyword, GHC will never attempt to derive a class using the `DeriveAnyClass` strategy when it would otherwise derive a `bespoke` instance, since it is guaranteed that doing so would not produce the instance you'd want. This also applies when deriving a bespoke instance for a newtype when both `-XGeneralizedNewtypeDeriving` and `-XDeriveAnyClass` are enabled, which is why we need step 2 to come before step 3 so that `-XDeriveAnyClass` doesn't kick in when it shouldn't. This fixes the problem originally reported in Trac [\#10598](https://gitlab.haskell.org//ghc/ghc/issues/10598).
|
|
|
|
|
|
|
|
|
To help visualize things, here's a table summarizing which typeclasses GHC decides it can use the `newtype` strategy for (thanks to Ørjan Johansen):
|
|
|
|
|
|
<table><tr><th> GND equivalence </th>
|
|
|
<th> No extension </th>
|
|
|
<th> Requires `-XGeneralizedNewtypeDeriving`</th>
|
|
|
<th> No extension required </th>
|
|
|
<th> Requires language extension to use
|
|
|
</th>
|
|
|
<th></th>
|
|
|
<th></th></tr>
|
|
|
<tr><th> Always </th>
|
... | ... | |