RFC for a change in EmptyDataDecls instance deriving
Ömer Sinan Ağacan
omeragacan at gmail.com
Wed Jul 15 15:56:23 UTC 2015
# RFC for a change in EmptyDataDecls instance deriving
Hi all,
There were some requests about EmptyDataDecls instance deriving and recently I
made some progress towards implementing those. However as I implement things
people started suggesting different behaviors than what I've implemented etc.
In the end, we thought it'd be a good idea to ask libraries mailing list for
which behavior to implement.
# Summary
Haskell 2010 doesn't support data types without any constructors(aka. empty
data type)[1]. GHC supports it via EmptyDataDecls[2], but it fails to derive
instances:
Decl.hs:3:18:
Can't make a derived instance of ‘Eq Z’:
‘Z’ must have at least one data constructor
Possible fix: use a standalone deriving declaration instead
In the data declaration for ‘Z’
Using StandaloneDeriving works, and it generates methods that calls `error`:
Derived instances:
instance GHC.Classes.Eq Main.Z where
(GHC.Classes.==) = GHC.Err.error "Void =="
(GHC.Classes./=) a_aCf b_aCg
= GHC.Classes.not ((GHC.Classes.==) a_aCf b_aCg)
Note that these methods fail in first applications. So `(==) a` is an error, it
doesn't need to be a fully saturated application.
Ticket 7401[3] asks for a change in default deriving mechanism. I submitted a
patch[4] that makes standard deriving work same as standalone deriving, for
empty data types. This is completely backwards-compatible change, since
previously deriving on empty data types wasn't working.(I also made some
improvements on error messages)
But then some people suggested that derived methods are not good, and we should
use empty pattern match in method bodies instead[5]. E.g. if we derive Eq for
an empty data type, generated instance should be:
instance Eq X where
a == b = case a of {}
See [5] for motivation.
So now we're also thinking about changing StandaloneDeriving for empty types
too, to use empty pattern match instead of `error`.
One thing to note is Data.Void.Void is doing completely different thing, it's
Eq is defined like this:
instance Eq Void where
_ == _ = True
So now that we have the story, my questions are:
1. What do you think is the right way to derive instances for empty data types?
An `error` or pattern match on bottom argument(e.g. empty case)?
2. Do you think with EmptyDataDecls and StandaloneDeriving, `deriving(..)` and
standalone deriving should derive same instances?
3. Should we change instances of Void on the way, for consistency? (Ord and Eq
especially)
My answers:
1. Empty case. Users can always implement instances manually for always
succeeding (==) etc.
2. Definitely. Current deriving mechanisms are already complex and it's hard to
predict interactions between them(see [6]), I think we should do our best to
keep them as simple as possible. Personally I'd hate it if standalone
deriving and `deriving(...)` would implement different instances.
3. No opinion. May break some code? But making the change might be good for
consistency?
If answers to (2) is yes, then we can just merge [4](which also improves error
messages), but if we want to change how we define instances too, then it'll
need some more work and I'll be working on that.
In any case, I think we should update the user manual to specify what will be
the derived instances. (as far as I can see currently it's not specified)
---
[1]: https://www.haskell.org/onlinereport/haskell2010/haskellch11.html#x18-18200011
[2]: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/data-type-extensions.html#nullary-types
[3]: https://ghc.haskell.org/trac/ghc/ticket/7401
[4]: https://phabricator.haskell.org/D978
[5]: https://ghc.haskell.org/trac/ghc/ticket/10577
[6]: https://ghc.haskell.org/trac/ghc/ticket/10598
More information about the Libraries
mailing list