[GHC] #14332: Deriving clauses can have forall types
GHC
ghc-devs at haskell.org
Mon Oct 9 10:49:25 UTC 2017
#14332: Deriving clauses can have forall types
-------------------------------------+-------------------------------------
Reporter: RyanGlScott | Owner: (none)
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler (Type | Version: 8.2.1
checker) |
Resolution: | Keywords: deriving
Operating System: Unknown/Multiple | Architecture:
Type of failure: GHC accepts | Unknown/Multiple
invalid program | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by RyanGlScott):
I'm well aware of the fact that `deriv_clause_tys` uses `LHsSigType`. That
is indeed there for a good reason—`deriving` clauses need to support
implicit quantification. But just because `LHsSigType` supports explicit
quantification via `forall`s doesn't mean it's a good idea to actually
allow them in `deriving` clauses. After all, the fact that we use
`LHsSigType` in class instances means that it's possible to write
instances with nested `forall`s, like this:
{{{#!hs
instance forall a. forall b. (Show a, Show b) => Show (Either a b)
}}}
But despite this, GHC will reject this will `Malformed instance: forall a.
forall b. Show (Either a b)`. Similarly, we should think carefully about
whether `deriving (forall <<>>. C c1 ... cn)` well formed or not.
I thought about this some more last night, and another reason why
`deriving (forall <<>>. C c1 ... cn)` bothers me is because unlike the
`forall` in a class instance, this proposed `forall` in a `deriving`
clause doesn't scope over a "real" type in some ways. That is to say, the
`C c1 ... cn` in `deriving C c1 ... cn` isn't so much of a type as a "type
former". There is a rather involved process in taking `C c1 ... cn`,
applying it to the datatype (possibly after eta reducing some of its type
variables), and unifying their kinds. In fact, after this kind
unification, it's possible that some of these type variables will vanish
completely! Take this example, for instance:
{{{#!hs
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeInType #-}
{-# OPTIONS_GHC -ddump-deriv #-}
class C k (a :: k)
data D = D deriving (C k)
}}}
Here, the actual instance that gets emitted (as shown by `-ddump-deriv`)
is:
{{{
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/ryanglscott/.ghci
[1 of 1] Compiling Main ( Bug.hs, interpreted )
==================== Derived instances ====================
Derived class instances:
instance Main.C * Main.D where
}}}
Notice how the `k` has become `*` due to kind unification! But according
to this proposal, you could have alternatively written this as:
{{{#!hs
data D = D deriving (forall k. C k)
}}}
And according to the specification given in comment:3, this should emit an
instance of the form `forall k. ... => C k D`. But that's clearly not true
when you inspect `-ddump-deriv`! So this `forall` here is an utter lie.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14332#comment:6>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list