GHC/Stand-alone deriving declarations
Bjorn Bringert has recently implemented "stand-alone deriving" declarations, documented briefly here . There are a few loose ends which I summarise here:
The current syntax is
deriving Show for T
There seems to be a consensus that this would be better:
derive instance Show T
so that it looks more like a regular instance declaration. Here
derive is not a new keyword; it's a "special-id", distinguished by the following
instance keyword. That means that
derive can still be used freely as a regular varid.
derived would sound more declarative than
Context on the declaration
Because it looks like a regular instance declaration, it would arguably be reasonable to require the programmer to supply the context. It seems odd to say:
derive instance Show (T a)
and perhaps cleaner to say
derive instance Show a => Show (T a)
(At the moment, the compiler figures out the appropriate context, but at some point that automation may run out of steam.)
Alternatively the syntax could be:
instance deriving Show a => Show (T a)
with the advantage that we don't need a complicated rule to determine whether or not
derive is an identifier or a keyword (all other reserved ids always occur inside the construct not before it), or even just
instance Show a => Show (T a)
where the fact that the compiler is automatically deriving the content of the instance declaration is implicit in the absence of a
Interaction with "newtype-deriving"
GHC's "newtype deriving mechanism" (see ) should obviously work in a standalone deriving setting too. But perhaps it can be generalised a little. Currently you can only say
deriving C a for Foo
(where Foo is the newtype), and get an instance for
(C a Foo). But what if you want and instance for
C Foo a, where the new type is not the last parameter. You can't do that at the moment. However, even with the new instance-like syntax, it's not clear to me how to signal the type to be derived. Consider
newtype Foo = F Int newtype Bar = B Bool derive instance C Foo Bar
Which of these thee instances do we want?
instance C Foo Bool => C Foo Bar instance C Int Bar => C Foo Bar instance C Int Bool => C Foo Bar
The obvious way to signal this is to give the instance context (just as above). This is perhaps another reason for having an explicit instance context in a standalone deriving declaration.
Incidentally, notice that the third of the alternatives in the previous bullet unwraps two newtypes simultaneously. John Meacham suggested this example:
class SetLike m k where instance SetLike IntSet Int where newtype Id = Id Int newtype IdSet = IdSet IntSet derive instance SetLike IntSet Int => SetLike IdSet Id
Suppose two modules, M1 and M2 both contain an identical standalone deriving declaration
derive Show T
Then, can you import M1 and M2 into another module X and use show on values of type T, or will you get an overlapping instance error? Since both instances are derived in the very same way, their code must be identical, so arguably we can choose either. (There is some duplicated code of course.)
This situation is expected to be common, as the main use of the standalone feature is to obtain derived instances that were omitted when the data type was defined.