
#16194: deriving, wrong code: newtype T cat a = MkT ((forall xx. cat xx xx) -> a) deriving stock Functor -------------------------------------+------------------------------------- Reporter: Iceland_jack | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.7 Resolution: | Keywords: DeriveFunctor | deriving RankNTypes Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by RyanGlScott): This is rather delicate. Here is the instance you likely have in your head: {{{#!hs instance Functor (T cat) where fmap f (MkT g) = MkT (\x -> f (g x)) }}} As `-ddump-deriv` reveals, this isn't quite the code that GHC is producing. It's actually producing this: {{{#!hs instance Functor (T cat) where fmap f (MkT g) = MkT ((\g' x -> f (g' x)) g) }}} Normally, these two implementations would be equivalent. However, because `g` has a higher-rank type `forall xx. cat xx xx`, applying `(\g' x -> f (g' x))` to `g` causes its type to be instantiated with a skolem `xx0`. This is why you get this error message: {{{ Couldn't match type ‘forall xx. cat xx xx’ with ‘cat xx0 xx0’ }}} There are advantages to generating code similar to the second instance. In more complicated examples (e.g., `newtype T a = MkT (Int -> Int -> a)`), using the unapplied form allows for a more compositional code-generation strategy that doesn't have to reason about substituting in arguments. In short, could this be fixed? Theoretically speaking, yes, but it would require a lot of work for not much gain. Personally, I'm inclined to just require users to write out this particular instance by hand. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/16194#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler