Closed RyanGlScott closed 3 years ago
Actually, this instance wouldn't kind-check even without the type-variable switcheroo. You'd end up with something like this:
instance Generic1 (Compose f g) where
type Rep1 (Compose f g) =
D1 (MetaData "Compose" "ModuleName" "package-name" True)
(C1 (MetaCons "Compose" 'PrefixI False)
(S1 (MetaSel Nothing NoSourceUnpackedness NoSourceStrictness DecidedLazy)
(f :.: Rec1 g)))
from1 (Compose x) = M1 (M1 (M1 (Comp1 (fmap Rec1 x))))
to1 (M1 (M1 (M1 x))) = Compose (fmap unRec1 (unComp1 x))
Which would fail thusly:
error:
• Couldn't match kind ‘k2’ with ‘*’
Expected kind ‘k -> *’, but ‘g’ has kind ‘k -> k2’
• In the first argument of ‘Rec1’, namely ‘g’
In the second argument of ‘(:.:)’, namely ‘Rec1 g’
In the second argument of ‘S1’, namely ‘(f :.: Rec1 g)’
|
| (f :.: Rec1 g)))
| ^
Perhaps there is a less complicated example we could check in as a test case, however.
Another example on this phenomenon occurs if you use GHC 8.0 specifically on this code:
λ> newtype T f a b = MkT (f a b)
λ> ; $(deriveAll1 ''T)
<interactive>:12:5-18: Splicing declarations
deriveAll1 ''T
======>
instance Generic1 (T (f_aCtp :: k_aCtw
-> GHC.Types.Type
-> GHC.Types.Type) (a_aCtq :: k_aCtw) :: GHC.Types.Type
-> GHC.Types.Type) where
type Rep1 (T (f_aCtp :: k_aCtw
-> GHC.Types.Type
-> GHC.Types.Type) (a_aCtq :: k_aCtw) :: GHC.Types.Type
-> GHC.Types.Type) = D1 (MetaData "T" "Ghci4" "interactive" True) (C1 (MetaCons "MkT" PrefixI False) (S1 (MetaSel Nothing NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec1 (a_aCtq a_aCtq))))
from1
= \ val_aCVi
-> case val_aCVi of {
y_aCVj
-> M1 (case y_aCVj of { MkT f1_aCVk -> M1 (M1 (Rec1 f1_aCVk)) }) }
to1
= \ val_aCVl
-> case val_aCVl of {
M1 y_aCVm
-> case y_aCVm of { M1 (M1 f1_aCVn) -> MkT (unRec1 f1_aCVn) } }
<interactive>:12:5: error:
• Occurs check: cannot construct the infinite kind: k ~ k -> * -> *
• In the first argument of ‘Rec1’, namely ‘a_aCtq a_aCtq’
In the second argument of ‘S1’, namely ‘Rec1 (a_aCtq a_aCtq)’
In the second argument of ‘C1’, namely
‘S1 (MetaSel Nothing NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec1 (a_aCtq a_aCtq))’
Note the (Rec1 (a_aCtq a_aCtq))
bit.
The Haddocks in
Generics.Deriving.TH
give the following example of how to usekindSigOptions
:https://github.com/dreixel/generic-deriving/blob/e858579e4f50bd2984b1ef7b736ad9f23279d4c1/src/Generics/Deriving/TH.hs#L135-L138
However, this doesn't seem to work in practice. If you compile the following file:
It will fail thusly:
The
((GHC.Generics.:.:) g_afKB (GHC.Generics.Rec1 g_afKB))
bit is flat-out wrong—that should be((GHC.Generics.:.:) f_afKA (GHC.Generics.Rec1 g_afKB))
instead. Curiously, thisg_afKB
-to-f_afKA
switcheroo doesn't happen whenkindSigOptions
isTrue
. Investigate why, fix it, and add a test case for it.