Difference between revisions of "GHC/Stand-alone deriving declarations"

From HaskellWiki
< GHC
Jump to navigation Jump to search
(alternative syntax suggestion)
Line 35: Line 35:
 
</haskell>
 
</haskell>
 
where the fact that the compiler is automatically deriving the content of the instance declaration is implicit in the absence of a <hask>where</hask> clause.
 
where the fact that the compiler is automatically deriving the content of the instance declaration is implicit in the absence of a <hask>where</hask> clause.
  +
  +
But, why is "derive" or "deriving" even needed? Why not just say an instance is a derived instance unless there is a body? The Haskell 98 instance syntax is:
  +
  +
<code>instance [scontext => ] qtycls inst [where idecls]</code>
  +
  +
I propose that you simply say that a derived instance is:
  +
  +
<code>instance [scontext => ] qtycls inst</code>
  +
  +
The body (where idecls) is already optional to accommodate simple classes without bodies. If a class does not have a body then you can say that all instances of it are derived trivially.
   
 
== Interaction with "newtype-deriving" ==
 
== Interaction with "newtype-deriving" ==
Line 76: Line 86:
   
 
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.
 
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.
  +
  +
But, that means whether or not an instance was derived is now part of the module's. Programs would be able to use this (mis)feature to perform a compile-time check and execute code differently depending on whether any given instance is derived or hand-coded:
  +
<haskell>
  +
module MA(A) where
  +
data A = A deriving Show
  +
  +
module MB(B) where
  +
data B = B deriving Show
  +
  +
module MC where
  +
import MA
  +
import MB
  +
  +
-- verify that the A and B Show instances were derived
  +
-- (they need to be derived to ensure the output can
  +
-- be parsed in our non-Haskell code).
  +
derive instance Show A
  +
derive instance Show B
  +
</haskell>
  +
The writer of MC already knows that MA and MB defined instances of Show for A and B. He just wants to ensure that nobody changes either module to use a non-derived instance; if someone does try to use a non-derived instance:
  +
<haskell>
  +
module MA(A) where
  +
data A = A
  +
instance Show A where
  +
show _ = "a"
  +
</haskell>
  +
then they will get an overlapping instance error in MC.
  +
  +
The result is that programs would be able to require, for any Class, not just that an instance of the class was defined for a type, but that a /derived/ instance was defined. Is this good?

Revision as of 17:55, 1 November 2006

Bjorn Bringert has recently implemented "stand-alone deriving" declarations, documented briefly here [1]. There are a few loose ends which I summarise here:

Syntax

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. (Perhaps derived would sound more declarative than derive.)

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 where clause.

But, why is "derive" or "deriving" even needed? Why not just say an instance is a derived instance unless there is a body? The Haskell 98 instance syntax is:

   instance [scontext => ] qtycls inst [where idecls]

I propose that you simply say that a derived instance is:

   instance [scontext => ] qtycls inst

The body (where idecls) is already optional to accommodate simple classes without bodies. If a class does not have a body then you can say that all instances of it are derived trivially.

Interaction with "newtype-deriving"

GHC's "newtype deriving mechanism" (see [2]) 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

Duplicate instances

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.

But, that means whether or not an instance was derived is now part of the module's. Programs would be able to use this (mis)feature to perform a compile-time check and execute code differently depending on whether any given instance is derived or hand-coded:

   module MA(A) where
   data A = A deriving Show
  
   module MB(B) where
   data B = B deriving Show

   module MC where
   import MA
   import MB

   -- verify that the A and B Show instances were derived
   -- (they need to be derived to ensure the output can
   -- be parsed in our non-Haskell code).
   derive instance Show A 
   derive instance Show B

The writer of MC already knows that MA and MB defined instances of Show for A and B. He just wants to ensure that nobody changes either module to use a non-derived instance; if someone does try to use a non-derived instance:

   module MA(A) where
   data A = A
   instance Show A where
       show _ = "a"

then they will get an overlapping instance error in MC.

The result is that programs would be able to require, for any Class, not just that an instance of the class was defined for a type, but that a /derived/ instance was defined. Is this good?