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