GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2024-02-23T23:14:26Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/24312Deriving Eq1 via Generically1 doesn't work and never did2024-02-23T23:14:26ZSergey VinokurovDeriving Eq1 via Generically1 doesn't work and never did## Summary
There's following instance for `Generically1` (perhaps originally taken from the `generic-data` package)
```haskell
(Generic1 f, Eq1 (Rep1 f)) => Eq1 (Generically1 f)
```
The constraint `Eq1 (Rep1 f)` is not satisfiable and...## Summary
There's following instance for `Generically1` (perhaps originally taken from the `generic-data` package)
```haskell
(Generic1 f, Eq1 (Rep1 f)) => Eq1 (Generically1 f)
```
The constraint `Eq1 (Rep1 f)` is not satisfiable and never was because auxiliary Generics types like `M1` (aka `D1` in the error below) don't have `Eq1` instance.
NB The same applies to `Ord1`. Also there's no `Show1` instance for `Generically1`.
## Steps to reproduce
Take following program
```haskell
#!/usr/bin/env cabal
{- cabal:
build-depends:
, base
default-language:
Haskell2010
ghc-options:
-main-is Test
-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE TypeApplications #-}
module Test (main) where
import Data.Functor.Classes
import GHC.Generics (Generic1, Generically1(..))
data I a = I [a] (Maybe a)
deriving stock (Eq, Ord, Show, Generic1)
deriving (Eq1) via (Generically1 I)
main :: IO ()
main = do
let x = I @Int [1, 2] (Just 3)
y = I @Int [] Nothing
putStrLn $ show $ eq1 x y
pure ()
```
And run it under GHC:
```
$ cabal run ./Test.hs
Created semaphore called cabal_semaphore_f with 32 slots.
/tmp/Test.hs:22:13: error: [GHC-39999]
• No instance for ‘Eq1
(GHC.Generics.D1
(GHC.Generics.MetaData
"I" "Test" "fake-package-0-inplace-script-Test.hs" False)
(GHC.Generics.C1
(GHC.Generics.MetaCons "I" GHC.Generics.PrefixI False)
(GHC.Generics.S1
(GHC.Generics.MetaSel
Nothing
GHC.Generics.NoSourceUnpackedness
GHC.Generics.NoSourceStrictness
GHC.Generics.DecidedLazy)
(GHC.Generics.Rec1 [])
GHC.Generics.:*: GHC.Generics.S1
(GHC.Generics.MetaSel
Nothing
GHC.Generics.NoSourceUnpackedness
GHC.Generics.NoSourceStrictness
GHC.Generics.DecidedLazy)
(GHC.Generics.Rec1 Maybe))))’
arising from the 'deriving' clause of a data type declaration
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
• When deriving the instance for (Eq1 I)
|
22 | deriving (Eq1) via (Generically1 I)
| ^^^
```
## Expected behavior
Print `False`, generally derive the `Eq1` instance without errors.
Probably either the `Eq1` instance for `Generically1` should be removed since it doesn't work and never did or *1 instances for `M1` and the rest should be added.
## Environment
* GHC version used: 9.8, 9.6, 9.4, 9.2, 8.10
Optional:
* Operating System: Linux
* System Architecture: x86_649.10.1https://gitlab.haskell.org/ghc/ghc/-/issues/23756Compile-time regression between GHC-9.2 and GHC-9.4 on generically deriving T...2023-08-25T16:47:50ZAndres LöhCompile-time regression between GHC-9.2 and GHC-9.4 on generically deriving TextShow instances## Summary
When porting a client project from ghc-9.2 (first to 9.6, then additionally to 9.4 to get more data), I noticed a pretty drastic compile time regression where the overall compile time of the project doubled (from roughly 8 to...## Summary
When porting a client project from ghc-9.2 (first to 9.6, then additionally to 9.4 to get more data), I noticed a pretty drastic compile time regression where the overall compile time of the project doubled (from roughly 8 to roughly 16 minutes). After a bit of investigation, I noticed that the slowdown is limited to a handful of modules. One of the worst affected modules had a number of derivations for `TextShow` instances using `DerivingVia`. So I'm singling out this part for now and reporting it as a bug.
After talking to @mpickering, I also did some additional experiments in how far the `text` version being used affects the overall outcome.
## Steps to reproduce
Here is a program that can be used to reproduce: it depends on `base` and `text-show`. I think even a smaller program with just a few of the datatypes already demonstrates the problem, but the time differences are less clearly observable, so I've opted for the larger sample here:
```haskell
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DerivingVia #-}
module Slow2 where
import GHC.Int
import qualified GHC.Generics as GHC
import TextShow
import TextShow.Generic
data SM =
CS !Int32 !Int32
| NS !Int32
deriving stock GHC.Generic
deriving TextShow via FromGeneric SM
data EM =
CE (Int, Int) (Int, Int)
| NE (Int, Int)
deriving stock GHC.Generic
deriving TextShow via FromGeneric EM
data AA = K | D | M
deriving stock GHC.Generic
deriving TextShow via FromGeneric AA
data AWA =
SI Int AA
| SP Int [AWA]
deriving stock GHC.Generic
deriving TextShow via FromGeneric AWA
data EEP =
EEP
{ eepP :: Int
, eepO :: Int
, eepB :: EM
, eepAWA :: [[AWA]]
}
deriving stock GHC.Generic
deriving TextShow via FromGeneric EEP
```
## Expected behavior
I would hope to see no drastic regression in compile times. As it is, here is a table of compile times
I have observed on my machine, split across various GHC versions and whether text-1 or text-2 is being
used:
| GHC version | Text version | Compile time |
|---|---|---|
| 9.2.7 | text-1.2.5.0 | 17.2s |
| 9.4.5 | text-1.2.5.0 | 35.1s |
| 9.6.2 | text-1.2.5.0 | 38.7s |
|||
| 9.2.7 | text-2.0.2 | 17.6s |
| 9.4.5 | text-2.0.2 | 45.7s |
| 9.6.2 | text-2.0.2 | 50.7s |
As can be seen, there is already a significant performance hit by just switching GHC versions, but it
seems to be an even bigger hit if text-2 is used (which originally I upgraded at the same time as the
GHC version, making the perceived hit even bigger).
## Environment
All on Linux, GHC versions and text versions as specified above.9.10.1Andreas KlebingerAndreas Klebingerhttps://gitlab.haskell.org/ghc/ghc/-/issues/21938Making inlining heuristics work for functions matching on nested data structu...2024-01-29T15:50:09ZAndreas KlebingerMaking inlining heuristics work for functions matching on nested data structures like generics.Currently GHC does a terrible job at inlining functions which take apart or branch on a known data structure in order to produce a small result.
## The problem
Consider one of the simplest nested data structures, inductively defined nu...Currently GHC does a terrible job at inlining functions which take apart or branch on a known data structure in order to produce a small result.
## The problem
Consider one of the simplest nested data structures, inductively defined numbers:
```
data Nat = Zero | Succ Nat
natToSmallInt :: Nat -> Int
natToSmallInt Zero = 0
natToSmallInt (Succ Zero) = 1
natToSmallInt (Succ (Succ Zero)) = 2
natToSmallInt (Succ (Succ (Succ Zero))) = 3
natToSmallInt (Succ (Succ (Succ (Succ Zero)))) = 4
natToSmallInt (Succ (Succ (Succ (Succ (Succ Zero))))) = 5
natToSmallInt (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))) = 6
natToSmallInt (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))) = 7
natToSmallInt (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))) = 8
natToSmallInt (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))))) = 9
natToSmallInt (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))))) = 10
natToSmallInt _ = error "Not Small"
foo :: Int
foo = natToSmallInt (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))))) -- 10 as argument
bar :: Int
bar = natToSmallInt Zero
```
We, as humans, can easily see that this function applied to any statically known argument will produce a small expression once we apply case of known constructor. However we don't inline `natToSmallInt` as the nested cases make it fairly large and we only apply a discount based on the argument once.
In a sense the issue is that GHC ignores how the function uses the components of it's argument, as well as GHC not considering the structure of the argument when computing the discount.
The end result is that we get:
```
-- RHS size: {terms: 12, types: 0, coercions: 0, joins: 0/0}
foo :: Int
[GblId,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=False, ConLike=False,
WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 120 0}]
foo
= natToSmallInt
(A.Succ
(A.Succ
(A.Succ
(A.Succ
(A.Succ (A.Succ (A.Succ (A.Succ (A.Succ (A.Succ A.Zero))))))))))
-- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
bar :: Int
[GblId,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=False, ConLike=False,
WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 20 0}]
bar = natToSmallInt A.Zero
```
Where we would have expected `foo = 10, bar = 0`
In practice this pattern arises (at least) with generics like described here: https://gitlab.haskell.org/ghc/ghc/-/issues/21457#note_445884 where we have a largish function taking apart a largish generic representation to select between a number of small rhs expressions.
### Option A: Improve inlining to account for nested data structures.
The only way I can (currently) think of to make this general pattern work well would be to have discounts based on the structure of arguments if they are known.
That is for natToSmallInt instead of generating this unfolding info:
```
-- RHS size: {terms: 71, types: 25, coercions: 4, joins: 0/0}
natToSmallInt :: Nat -> Int
[Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [40] 420 110}]
```
We generate argument guidance based on the shape of the argument. So rather than just using `[40]` we could generate somthing like:
```
[(Default:10,
Zero:190 [],
Succ:40
[ (Default:10
, Zero:140
, Succ:..)]
)]
```
Numbers are subject to change but in general the argument guidance could be computed by somthing along the lines of:
* Default: The discount we apply simply for knowing it's an evaluated argument so just a small discount.
* Zero: A known constructor which is a terminal for our discrimination.
+ Apply a decent discount to account for the branch being eliminated.
+ Apply an additional discount based on the size difference of the rhs if we apply case-of-known-constructor
using this constructor. This allows e.g. `natToSmallInt Zero` to inline.
* Succ: Similarly to the Zero case.
+ But additionally compute a discount for the constructors arguments given the alt-rhs we chose for `Succ`.
When we then see an application like `natToSmallInt (Succ Zero)` we compute the discount by:
* Apply the `Default` discount since the argument is evaluated.
* Apply the relevant constructor discount if any.
* Apply the relevant discounts for the constructor arguments recursively.
* Add up all these discounts as usual and make a decision.
I think this should work. But there is of course concern for impact on compile time. In particular we likely don't want to compute individual argument guidance on cases with >100 alternatives, or types with >100 arguments.
But having a (somewhat arbitrary) cutoff to achieve this seems reasonable.
### Option B: Solve this by making SpecConstr apply more liberally.
SpecConstr is actually **very** well equipped to handle cases like these already. Although it has a number of issues which prevent it from being a direct solution.
* It's not always applied e.g. top level non-recursive definitions like `natToSmallInt` don't get any benefit currently (see https://gitlab.haskell.org/ghc/ghc/-/issues/21457).
* It's not enabled by default at `-O` since it can destroy sharing.
* It can destroy sharing.
* It is by default limited to **3** specializations of a function. For `natToSmallInt` we would want 10 at least. For more complex types like generic instances this number increases rapidly.
* SpecConstr only considers the size of the *input* when deciding if something is worth specializing for. Although perhaps that can/should be fixed by applying a discount in a fashion similar to what I describe above for inlining.
* It's only run once while we apply inlining often and very opportunistically.
* **It doesn't work across modules**
So imo in order for SpecConstr to even be an option for addressing this we need to:
* Make it work across module boundaries.
* Have it work for arbitrarily large input bindings if we can tell that they will optimize to a small rhs when specialized. (E.g apply discounts similar to described above for inlining).
* Remove the limit on number of specializations. However this likely also requires us to implement some sort of heuristic/cost model that prevents GHC from generating an insurmountable number of relatively useless specializations.
* Improve the issue of it destroying sharing at least enough to make it safe to enable for -O
Overall this seems less doable than improving inlining.https://gitlab.haskell.org/ghc/ghc/-/issues/21933Binary instances are too large2023-02-17T14:43:29ZSimon Peyton JonesBinary instances are too largeSee also
* #22054
* #21938
Consider this example, taken from [here](https://gitlab.haskell.org/ghc/ghc/-/issues/21839#note_442468) in #21839, and the perf test in !8734.
```
{-# LANGUAGE DeriveGeneric #-}
{-# OPTIONS_GHC #-}
module Exa...See also
* #22054
* #21938
Consider this example, taken from [here](https://gitlab.haskell.org/ghc/ghc/-/issues/21839#note_442468) in #21839, and the perf test in !8734.
```
{-# LANGUAGE DeriveGeneric #-}
{-# OPTIONS_GHC #-}
module Example
( -- PathComponent(..)
PathTemplateVariable(..)
) where
import GHC.Generics
import Data.Typeable
import Data.Binary
data PathTemplateVariable =
VarA
| VarB
| VarC
| VarD
| Var1
| Var2
| Var3
| Var4
| Var5
| Var6
| Var7
| Var8
-- etc
deriving (Generic)
instance Binary PathTemplateVariable
```
This compiles significantly slower with HEAD than with ghc-9.4. See #21839.
I have established that there is zero difference from the `deriving( Generic )`. It's all the `Binary` instance.
This is odd. Really, the binary instance for `PathTemplateVariable` should boil down to
```
put VarA = write 1#
put VarB = write 2#
...
put Var8 = write 77#
```
It's a bit bonkers that it's so voluminous, even in ghc-9.4, let alone HEAD.
Understanding what's going on would require digging into
* The `binary` library
* The `bytestring` library
* The `Generics` implementation
so it's not the work of a moment. But it could be rewarding. Lots of people would be thrilled if these binary instances weren't so crushingly huge.https://gitlab.haskell.org/ghc/ghc/-/issues/21131Trouble specializing generic functions with extra arguments or constraints2023-03-26T03:58:54ZDavid FeuerTrouble specializing generic functions with extra arguments or constraints## Summary
Generic-derived methods for recursively defined types can't specialize to extra constraints.
## Steps to reproduce
```haskell
{-# options_ghc -O2 -ddump-simpl -dsuppress-coercions -dsuppress-type-applications #-}
{-# langua...## Summary
Generic-derived methods for recursively defined types can't specialize to extra constraints.
## Steps to reproduce
```haskell
{-# options_ghc -O2 -ddump-simpl -dsuppress-coercions -dsuppress-type-applications #-}
{-# language DeriveGeneric #-}
module Aha where
import Control.DeepSeq
import GHC.Generics
data MyList a = Nil | Cons a (MyList a)
deriving Generic
instance NFData a => NFData (MyList a)
```
Compiling this, I get
```haskell
Rec {
-- RHS size: {terms: 15, types: 13, coercions: 2, joins: 0/0}
Aha.$fNFDataMyList_$crnf [Occ=LoopBreaker]
:: forall a. NFData a => MyList a -> ()
[GblId, Arity=2, Str=<LCL(A)><1L>, Unf=OtherCon []]
Aha.$fNFDataMyList_$crnf
= \ (@a_a3bP)
($dNFData_a3bQ :: NFData a_a3bP)
(eta_B0 :: MyList a_a3bP) ->
case eta_B0 of {
Nil -> GHC.Tuple.();
Cons g1_a39r g2_a39s ->
case ($dNFData_a3bQ `cast` <Co:2>) g1_a39r of { () ->
Aha.$fNFDataMyList_$crnf $dNFData_a3bQ g2_a39s
}
}
end Rec }
```
Uh oh... this is a loop breaker with no unfolding, so it can't specialize to the underlying `NFData a` instance!
## Expected behavior
I would expect specialization (or something?) to effectively apply the static argument transformation to the `NFData a` dictionary, pulling it out of the loop. Unfortunately, that will do nothing for higher-order functions like generic versions of `traverse`; I have no clue how to approach specializing those to their arguments without a more general fix to the static argument issue.
## Environment
* GHC version used: 9.2.1
Optional:
* Operating System:
* System Architecture:https://gitlab.haskell.org/ghc/ghc/-/issues/20881Generics: Documentation of `:.:` + formulate `Rec1` in terms of `:.:` and `Pa...2021-12-29T10:32:54ZSebastian GrafGenerics: Documentation of `:.:` + formulate `Rec1` in terms of `:.:` and `Par1`?I was a bit confused when I investigated the `Rep1` representation of the following nested datatype:
```hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveFunctor #-}
module Lib where
import GHC.Generics
data Fork a = Fork a a
de...I was a bit confused when I investigated the `Rep1` representation of the following nested datatype:
```hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveFunctor #-}
module Lib where
import GHC.Generics
data Fork a = Fork a a
deriving (Generic, Functor, Generic1)
data Perfect a = Zero a | Succ (Perfect (Fork a))
deriving (Generic, Functor, Generic1)
```
In GHCi, I get (after stripping off metadata)
```
> :kind! Rep1 Perfect
Rep1 Perfect :: * -> *
= Par1 :+: (Perfect :.: Rec1 Fork)
```
Similarly to the definition of rose trees in https://hackage.haskell.org/package/base-4.16.0.0/docs/GHC-Generics.html#g:17, we get a `:.:` due to the nesting. But what I found confusing is the lack of `Rec1` around the left arg of `:.:`, `Perfect`. I assumed that similar to `:*:`, both left and right args of `:.:` would be ... well, some type constructor used in the result of `Rep1`, for which we have no explicit kind (which IMO makes GHC.Generics a bit awkward to use, because you never know whether you have matched on all type constructors that can happen in a `Rep1`).
But in this case, clearly the RHS of `:.:` is such a type constructor of the `Rep1` result kind (`Rec1 Fork`), whereas the LHS `Perfect` *is not*! It doesn't have the "pseudo-/sub-kind" of `* -> *` I would have expected; it is in fact an arbitrary type of kind `* -> *`.
So I read the original paper on the Generics impl and there we have
![grafik](/uploads/50a9c648ba7fda0469964de2f457b2f8/grafik.png)
Note the `arg` function. When it sees a field type such as `Perfect (Fork a)`, it matches the fourth GRHS, because `isRep1 Perfect` holds (because it has a `Rep1` instance) and `Fork a` is neither ground (it mentions the parameter `a`), nor *exactly* the parameter `a` (in which case it would match the third GRHS, as it does for `Fork a`).
That suggests that indeed, the LHS of `:.:` is an arbitrary type constructor of kind `* -> *` which has a `Generic1` instance. I wish that the documentation for `:.:` mentioned this asymmetry!
And now that I think of it, why do we need `Rec1` in the first place? The way I see it, `Rec1 f` is literally just `f :.: Par1`. We'd get
```
> :kind! Rep1 Perfect
Rep1 Perfect :: * -> *
= Par1 :+: (Perfect :.: (Perfect :.: Par1))
```
I guess `:.:` is a bit more complex to think about and only relevant in the nested data type case at the moment. Nevertheless, a good design would force you to think about `:.:` in generic functions from the get go. The programmer then would match on `f :.: Par1` only if they really can't come up with a polymorphically recursive function that properly handles `:.:`.
So I have two requests:
1. Update the documentation to reflect the asymmetry of `:.:`, namely that the LHS is always a type constructor that has a `Generic1`/`Rep1` instance, whereas the RHS is a `Rep1` generic view.
2. Deprecate `Rec1` in favor of `(:.: Par1)`, just as we deprecated `Par0` in favor of `Rec0`.
I really want (1), I don't necessarily need (2). Although (2) means that we end up with `Rec0` and `Par1`, which is a bit strange. Maybe we should simply name the former `K` and the latter `P`?https://gitlab.haskell.org/ghc/ghc/-/issues/20497Change kind specificities for generics2022-02-10T00:39:16ZDavid FeuerChange kind specificities for generics## Motivation
When using `TypeApplications` with `GHC.Generics`, it's useful to specify the types explicitly. It's not so useful to specify the *kinds* explicitly. For example, `to1 @Maybe` would be helpful, but actually you have to wri...## Motivation
When using `TypeApplications` with `GHC.Generics`, it's useful to specify the types explicitly. It's not so useful to specify the *kinds* explicitly. For example, `to1 @Maybe` would be helpful, but actually you have to write `to1 @_ @Maybe`, or `to1 @Type @Maybe`, to do that.
## Proposal
Write kind signatures for `Generic1` and the `Generic` components to mark kinds inferred:
```haskell
type Generic1 :: forall {k}. (k -> Type) -> k -> Type
type K1 :: forall {k}. Type -> Type -> k -> Type
-- et cetera
```Ben GamariHerbert Valerio Riedelhvr@gnu.orgCarter SchonwaldEmily PillmoreAndrew MartinchessaicgibbardglguyEdward KmettGeorge WilsonBen Gamarihttps://gitlab.haskell.org/ghc/ghc/-/issues/20106Type.Reflection code takes long to compile (48s on 8.10, 12s on 9.3)2022-12-02T22:31:47ZIcelandjackType.Reflection code takes long to compile (48s on 8.10, 12s on 9.3)This code takes around 48s to compile on ghc 8.10 and around 12s to compile on ghc 9.3.20210709. Maybe this is something you are interested in taking a closer look at. The example relies heavily on `Type.Reflection`, I have not minimized...This code takes around 48s to compile on ghc 8.10 and around 12s to compile on ghc 9.3.20210709. Maybe this is something you are interested in taking a closer look at. The example relies heavily on `Type.Reflection`, I have not minimized it but I am attempting to define generic implementations without using an adhoc typeclass definition.
```haskell
{-# Language FlexibleContexts #-}
{-# Language GADTs #-}
{-# Language PatternSynonyms #-}
{-# Language PolyKinds #-}
{-# Language ScopedTypeVariables #-}
{-# Language StandaloneKindSignatures #-}
{-# Language TypeApplications #-}
{-# Language TypeOperators #-}
{-# Language ViewPatterns #-}
import qualified GHC.Generics as GHC
import GHC.Generics hiding (Constructor, S)
import Type.Reflection
import Data.Kind
is :: forall a b. Typeable a => TypeRep b -> Maybe (a :~~: b)
is = eqTypeRep (typeRep @a)
gcountFields :: forall f a. Typeable @(Type -> Type) f => f a -> Int
gcountFields as
| (is @(V1 @Type) -> Just HRefl) <- typeRep @f
= 0
| (is @(U1 @Type) -> Just HRefl) <- typeRep @f
= 1
| k1 `App` TypeRep `App` TypeRep <- typeRep @f
, (is @(K1 @Type) -> Just HRefl) <- k1
= 1
| m1 `App` i `App` c `App` TypeRep <- typeRep @f
, (is @(M1 @Type) -> Just HRefl) <- m1
, M1 a <- as
= gcountFields a
| or `App` TypeRep `App` TypeRep <- typeRep @f
, (is @((:+:) @Type) -> Just HRefl) <- or
= case as of
L1 a -> gcountFields a
R1 a -> gcountFields a
| and `App` TypeRep `App` TypeRep <- typeRep @f
, (is @((:*:) @Type) -> Just HRefl) <- and
, a :*: b <- as
= gcountFields a + gcountFields b
countFields :: Generic a => Typeable (Rep a) => a -> Int
countFields = gcountFields . from
{-
-- Uncomment for versions before TypeRep was added to base
type TypeableInstance :: forall k. k -> Type
data TypeableInstance :: forall k. k -> Type where
TypeableInstance :: Typeable a => TypeableInstance a
typeableInstance :: forall (k :: Type) (a :: k). TypeRep a -> TypeableInstance a
typeableInstance rep = withTypeable rep TypeableInstance
pattern TypeRep :: forall (k :: Type) (a :: k). () => Typeable a => TypeRep a
pattern TypeRep <- (typeableInstance -> TypeableInstance)
where TypeRep = typeRep
-}
```https://gitlab.haskell.org/ghc/ghc/-/issues/15969Generic1 deriving should use more coercions2022-06-19T21:04:37ZDavid FeuerGeneric1 deriving should use more coercionsConsider
```hs
newtype Foo a = Foo (Maybe [a]) deriving (Generic1)
```
This produces some rather unsatisfactory Core:
```
-- to1 worker
Travv.$fGeneric1Foo1 :: forall a. Rep1 Foo a -> Maybe [a]
Travv.$fGeneric1Foo1
= \ (@ a_a7RL) (d...Consider
```hs
newtype Foo a = Foo (Maybe [a]) deriving (Generic1)
```
This produces some rather unsatisfactory Core:
```
-- to1 worker
Travv.$fGeneric1Foo1 :: forall a. Rep1 Foo a -> Maybe [a]
Travv.$fGeneric1Foo1
= \ (@ a_a7RL) (ds_d9dZ :: Rep1 Foo a_a7RL) ->
case ds_d9dZ `cast` <Co:103> of {
Nothing -> GHC.Maybe.Nothing @ [a_a7RL];
Just a1_a9fD -> GHC.Maybe.Just @ [a_a7RL] (a1_a9fD `cast` <Co:5>)
}
-- from1 worker
Travv.$fGeneric1Foo2 :: forall a. Foo a -> Maybe (Rec1 [] a)
Travv.$fGeneric1Foo2
= \ (@ a_a7R6) (x_a7GJ :: Foo a_a7R6) ->
case x_a7GJ `cast` <Co:2> of {
Nothing -> GHC.Maybe.Nothing @ (Rec1 [] a_a7R6);
Just a1_a9fD ->
GHC.Maybe.Just @ (Rec1 [] a_a7R6) (a1_a9fD `cast` <Co:6>)
}
```
Both of these functions could be implemented as safe coercions, but neither of them is! Similarly, if I define
```hs
data Bar a = Bar (Maybe [a]) deriving Generic1
```
I get a `to1` worker that looks like
```
Travv.$fGeneric1Bar_$cto1 :: forall a. Rep1 Bar a -> Bar a
Travv.$fGeneric1Bar_$cto1
= \ (@ a_a7UA) (ds_d9ho :: Rep1 Bar a_a7UA) ->
Travv.Bar
@ a_a7UA
(case ds_d9ho `cast` <Co:103> of {
Nothing -> GHC.Maybe.Nothing @ [a_a7UA];
Just a1_a9iK -> GHC.Maybe.Just @ [a_a7UA] (a1_a9iK `cast` <Co:5>)
})
```
That `case` expression should really just be a cast.
I think the basic trick is probably to inspect the role of the type argument of each type in a composition, using that to work out whether to coerce that step.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.6.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | RyanGlScott |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Generic1 deriving should use more coercions","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"8.8.1","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":["Generics"],"differentials":[],"test_case":"","architecture":"","cc":["RyanGlScott"],"type":"Bug","description":"Consider\r\n\r\n{{{#!hs\r\nnewtype Foo a = Foo (Maybe [a]) deriving (Generic1)\r\n}}}\r\n\r\nThis produces some rather unsatisfactory Core:\r\n\r\n{{{\r\n-- to1 worker\r\nTravv.$fGeneric1Foo1 :: forall a. Rep1 Foo a -> Maybe [a]\r\nTravv.$fGeneric1Foo1\r\n = \\ (@ a_a7RL) (ds_d9dZ :: Rep1 Foo a_a7RL) ->\r\n case ds_d9dZ `cast` <Co:103> of {\r\n Nothing -> GHC.Maybe.Nothing @ [a_a7RL];\r\n Just a1_a9fD -> GHC.Maybe.Just @ [a_a7RL] (a1_a9fD `cast` <Co:5>)\r\n}\r\n\r\n-- from1 worker\r\nTravv.$fGeneric1Foo2 :: forall a. Foo a -> Maybe (Rec1 [] a)\r\nTravv.$fGeneric1Foo2\r\n = \\ (@ a_a7R6) (x_a7GJ :: Foo a_a7R6) ->\r\n case x_a7GJ `cast` <Co:2> of {\r\n Nothing -> GHC.Maybe.Nothing @ (Rec1 [] a_a7R6);\r\n Just a1_a9fD ->\r\n GHC.Maybe.Just @ (Rec1 [] a_a7R6) (a1_a9fD `cast` <Co:6>)\r\n }\r\n}}}\r\n\r\nBoth of these functions could be implemented as safe coercions, but neither of them is! Similarly, if I define\r\n\r\n{{{#!hs\r\ndata Bar a = Bar (Maybe [a]) deriving Generic1\r\n}}}\r\n\r\nI get a `to1` worker that looks like\r\n\r\n{{{\r\nTravv.$fGeneric1Bar_$cto1 :: forall a. Rep1 Bar a -> Bar a\r\nTravv.$fGeneric1Bar_$cto1\r\n = \\ (@ a_a7UA) (ds_d9ho :: Rep1 Bar a_a7UA) ->\r\n Travv.Bar\r\n @ a_a7UA\r\n (case ds_d9ho `cast` <Co:103> of {\r\n Nothing -> GHC.Maybe.Nothing @ [a_a7UA];\r\n Just a1_a9iK -> GHC.Maybe.Just @ [a_a7UA] (a1_a9iK `cast` <Co:5>)\r\n })\r\n}}}\r\n\r\nThat `case` expression should really just be a cast.\r\n\r\nI think the basic trick is probably to inspect the role of the type argument of each type in a composition, using that to work out whether to coerce that step.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/15310Derive Generic1 instances for types of kind (k -> *) -> * that include applic...2019-07-07T18:13:20ZcedricshockDerive Generic1 instances for types of kind (k -> *) -> * that include applications of the parameterThe `Generic1` class is polykinded. The `DeriveGeneric` extension can derive `Generic1` instances for types of kind `k -> *` parameterized over a parameter with a kind other than `k ~ *`, but only if they don't apply the parameter to oth...The `Generic1` class is polykinded. The `DeriveGeneric` extension can derive `Generic1` instances for types of kind `k -> *` parameterized over a parameter with a kind other than `k ~ *`, but only if they don't apply the parameter to other types.
It currently cannot derive an instance for
```hs
newtype Fix f = In (f (Fix f))
deriving (Generic1)
```
or for
```hs
data Child f = Child {
ordinal :: Int,
nickname :: f String
}
deriving (Generic1)
```
It's possible to represent these types generically, either with composition that can include occurrences of the parameter or with new types that represent applications of the parameter.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ----------------------- |
| Version | |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | low |
| Resolution | Unresolved |
| Component | Compiler (Type checker) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Derive Generic1 instances for types of kind (k -> *) -> * that include applications of the parameter","status":"New","operating_system":"","component":"Compiler (Type checker)","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"","keywords":["DeriveGeneric","Generic1"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"The `Generic1` class is polykinded. The `DeriveGeneric` extension can derive `Generic1` instances for types of kind `k -> *` parameterized over a parameter with a kind other than `k ~ *`, but only if they don't apply the parameter to other types.\r\n\r\nIt currently cannot derive an instance for\r\n\r\n{{{#!hs\r\nnewtype Fix f = In (f (Fix f))\r\n deriving (Generic1)\r\n}}}\r\n\r\nor for \r\n\r\n{{{#!hs\r\ndata Child f = Child {\r\n ordinal :: Int,\r\n nickname :: f String\r\n}\r\n deriving (Generic1)\r\n}}}\r\n\r\nIt's possible to represent these types generically, either with composition that can include occurrences of the parameter or with new types that represent applications of the parameter.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/13065Prohibit user-defined Generic and Generic1 instances2020-01-23T19:32:34ZDavid FeuerProhibit user-defined Generic and Generic1 instancesUser-defined `Generic` and `Generic1` instances are problematic.
### They are susceptible to breakage
Some details of the classes may change between GHC versions, and indeed have done so in the past. User-defined instances are likely t...User-defined `Generic` and `Generic1` instances are problematic.
### They are susceptible to breakage
Some details of the classes may change between GHC versions, and indeed have done so in the past. User-defined instances are likely to break in the face of various such "internal" changes. This is one reason why `Data.Sequence`, for example, does not have a `Generic` instance.
### They require potentially-expensive consistency checks
GHC cannot assume that every type has at most one `Generic` and `Generic1` instance, so it needs to look for possible alternatives at instance resolution time. According to Simon (and maybe also Simon), this may be partly responsible for the performance regressions seen in [D2899](https://phabricator.haskell.org/D2899).
### Downsides
Prohibiting user-defined instances does have some costs. Suppose a type was originally defined concretely, exposing its constructors and a `Generic` instance. The implementer may decide later to make the type abstract, and export pattern synonyms to retain the same interface. But the `Generic` instance will either change or disappear. Someone relying on that instance could be in trouble. If the instance disappears, they'll be forced to write code by hand that they didn't need to before. If it changes, their code may change its behavior unexpectedly.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 8.0.1 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Prohibit user-defined Generic and Generic1 instances","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"8.4.1","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.0.1","keywords":["Generics"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"User-defined `Generic` and `Generic1` instances are problematic.\r\n\r\n=== They are susceptible to breakage ===\r\nSome details of the classes may change between GHC versions, and indeed have done so in the past. User-defined instances are likely to break in the face of various such \"internal\" changes. This is one reason why `Data.Sequence`, for example, does not have a `Generic` instance.\r\n\r\n=== They require potentially-expensive consistency checks ===\r\nGHC cannot assume that every type has at most one `Generic` and `Generic1` instance, so it needs to look for possible alternatives at instance resolution time. According to Simon (and maybe also Simon), this may be partly responsible for the performance regressions seen in Phab:D2899.\r\n\r\n=== Downsides ===\r\nProhibiting user-defined instances does have some costs. Suppose a type was originally defined concretely, exposing its constructors and a `Generic` instance. The implementer may decide later to make the type abstract, and export pattern synonyms to retain the same interface. But the `Generic` instance will either change or disappear. Someone relying on that instance could be in trouble. If the instance disappears, they'll be forced to write code by hand that they didn't need to before. If it changes, their code may change its behavior unexpectedly.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/10514Generic for existential types2021-01-24T15:31:27Zandreas.abelGeneric for existential typesI have some use for Generic for an existential type which is constraint to be Generic.
```hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE StandaloneDeriving #-}
import GHC.Generics
data U = fo...I have some use for Generic for an existential type which is constraint to be Generic.
```hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE StandaloneDeriving #-}
import GHC.Generics
data U = forall a. (Generic a) => U a
deriving (Generic) -- TRY 1
-- Can't make a derived instance of ‘Generic U’:
-- Constructor ‘U’ has existentials or constraints in its type
-- Possible fix: use a standalone deriving declaration instead
deriving instance Generic U -- TRY 2
-- Can't make a derived instance of ‘Generic U’:
-- U must be a vanilla data constructor
-- In the stand-alone deriving instance for ‘Generic U’
data D1Ser
data C1_0Ser
instance Generic U where -- TRY 3
type Rep U = D D1Ser (C1 C1_0Ser (S1 NoSelector (Rep a)))
-- Not in scope: type variable ‘a’
-- How to bring the existential type `a' into scope?
```Edward KmettEdward Kmetthttps://gitlab.haskell.org/ghc/ghc/-/issues/5642Deriving Generic of a big type takes a long time and lots of space2024-03-28T13:22:28ZbasvandijkDeriving Generic of a big type takes a long time and lots of spaceIf I load the following module into `ghci` my system will run out of memory after about 15 minutes:
```
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
data BigSum =
C0 | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 ...If I load the following module into `ghci` my system will run out of memory after about 15 minutes:
```
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
data BigSum =
C0 | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 | C9
| C10 | C11 | C12 | C13 | C14 | C15 | C16 | C17 | C18 | C19
| C20 | C21 | C22 | C23 | C24 | C25 | C26 | C27 | C28 | C29
| C30 | C31 | C32 | C33 | C34 | C35 | C36 | C37 | C38 | C39
| C40 | C41 | C42 | C43 | C44 | C45 | C46 | C47 | C48 | C49
| C50 | C51 | C52 | C53 | C54 | C55 | C56 | C57 | C58 | C59
| C60 | C61 | C62 | C63 | C64 | C65 | C66 | C67 | C68 | C69
| C70 | C71 | C72 | C73 | C74 | C75 | C76 | C77 | C78 | C79
| C80 | C81 | C82 | C83 | C84 | C85 | C86 | C87 | C88 | C89
| C90 | C91 | C92 | C93 | C94 | C95 | C96 | C97 | C98 | C99
| C100 | C101 | C102 | C103 | C104 | C105 | C106 | C107 | C108 | C109
| C110 | C111 | C112 | C113 | C114 | C115 | C116 | C117 | C118 | C119
| C120 | C121 | C122 | C123 | C124 | C125 | C126 | C127 | C128 | C129
| C130 | C131 | C132 | C133 | C134 | C135 | C136 | C137 | C138 | C139
| C140 | C141 | C142 | C143 | C144 | C145 | C146 | C147 | C148 | C149
| C150 | C151 | C152 | C153 | C154 | C155 | C156 | C157 | C158 | C159
| C160 | C161 | C162 | C163 | C164 | C165 | C166 | C167 | C168 | C169
| C170 | C171 | C172 | C173 | C174 | C175 | C176 | C177 | C178 | C179
| C180 | C181 | C182 | C183 | C184 | C185 | C186 | C187 | C188 | C189
| C190 | C191 | C192 | C193 | C194 | C195 | C196 | C197 | C198 | C199
| C200 | C201 | C202 | C203 | C204 | C205 | C206 | C207 | C208 | C209
| C210 | C211 | C212 | C213 | C214 | C215 | C216 | C217 | C218 | C219
| C220 | C221 | C222 | C223 | C224 | C225 | C226 | C227 | C228 | C229
| C230 | C231 | C232 | C233 | C234 | C235 | C236 | C237 | C238 | C239
| C240 | C241 | C242 | C243 | C244 | C245 | C246 | C247 | C248 | C249
| C250 | C251 | C252 | C253 | C254 | C255 | C256 | C257 | C258 | C259
| C260 | C261 | C262 | C263 | C264 | C265 | C266 | C267 | C268 | C269
| C270 | C271 | C272 | C273 | C274 | C275 | C276 | C277 | C278 | C279
| C280 | C281 | C282 | C283 | C284 | C285 | C286 | C287 | C288 | C289
| C290 | C291 | C292 | C293 | C294 | C295 | C296 | C297 | C298 | C299
deriving Generic
```
Big products have the same problem:
```
data BigProduct = C
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
deriving Generic
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.2.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | dreixel |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Deriving Generic of a big type takes a long time and lots of space","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.2.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":["dreixel"],"type":"Bug","description":"If I load the following module into `ghci` my system will run out of memory after about 15 minutes: \r\n\r\n{{{\r\n{-# LANGUAGE DeriveGeneric #-}\r\n\r\nimport GHC.Generics\r\n\r\ndata BigSum = \r\n C0 | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 | C9 \r\n | C10 | C11 | C12 | C13 | C14 | C15 | C16 | C17 | C18 | C19 \r\n | C20 | C21 | C22 | C23 | C24 | C25 | C26 | C27 | C28 | C29\r\n | C30 | C31 | C32 | C33 | C34 | C35 | C36 | C37 | C38 | C39\r\n | C40 | C41 | C42 | C43 | C44 | C45 | C46 | C47 | C48 | C49\r\n | C50 | C51 | C52 | C53 | C54 | C55 | C56 | C57 | C58 | C59\r\n | C60 | C61 | C62 | C63 | C64 | C65 | C66 | C67 | C68 | C69\r\n | C70 | C71 | C72 | C73 | C74 | C75 | C76 | C77 | C78 | C79\r\n | C80 | C81 | C82 | C83 | C84 | C85 | C86 | C87 | C88 | C89\r\n | C90 | C91 | C92 | C93 | C94 | C95 | C96 | C97 | C98 | C99\r\n | C100 | C101 | C102 | C103 | C104 | C105 | C106 | C107 | C108 | C109\r\n | C110 | C111 | C112 | C113 | C114 | C115 | C116 | C117 | C118 | C119\r\n | C120 | C121 | C122 | C123 | C124 | C125 | C126 | C127 | C128 | C129\r\n | C130 | C131 | C132 | C133 | C134 | C135 | C136 | C137 | C138 | C139\r\n | C140 | C141 | C142 | C143 | C144 | C145 | C146 | C147 | C148 | C149\r\n | C150 | C151 | C152 | C153 | C154 | C155 | C156 | C157 | C158 | C159\r\n | C160 | C161 | C162 | C163 | C164 | C165 | C166 | C167 | C168 | C169\r\n | C170 | C171 | C172 | C173 | C174 | C175 | C176 | C177 | C178 | C179\r\n | C180 | C181 | C182 | C183 | C184 | C185 | C186 | C187 | C188 | C189\r\n | C190 | C191 | C192 | C193 | C194 | C195 | C196 | C197 | C198 | C199\r\n | C200 | C201 | C202 | C203 | C204 | C205 | C206 | C207 | C208 | C209\r\n | C210 | C211 | C212 | C213 | C214 | C215 | C216 | C217 | C218 | C219\r\n | C220 | C221 | C222 | C223 | C224 | C225 | C226 | C227 | C228 | C229\r\n | C230 | C231 | C232 | C233 | C234 | C235 | C236 | C237 | C238 | C239\r\n | C240 | C241 | C242 | C243 | C244 | C245 | C246 | C247 | C248 | C249\r\n | C250 | C251 | C252 | C253 | C254 | C255 | C256 | C257 | C258 | C259\r\n | C260 | C261 | C262 | C263 | C264 | C265 | C266 | C267 | C268 | C269\r\n | C270 | C271 | C272 | C273 | C274 | C275 | C276 | C277 | C278 | C279\r\n | C280 | C281 | C282 | C283 | C284 | C285 | C286 | C287 | C288 | C289\r\n | C290 | C291 | C292 | C293 | C294 | C295 | C296 | C297 | C298 | C299\r\n deriving Generic\r\n}}}\r\n\r\nBig products have the same problem:\r\n\r\n{{{\r\ndata BigProduct = C \r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n () () () () () () () () () ()\r\n deriving Generic\r\n}}}\r\n","type_of_failure":"OtherFailure","blocking":[]} -->⊥