Derived Functor instance for void types

Ryan Scott ryan.gl.scott at gmail.com
Mon Jan 16 14:25:13 UTC 2017


To be clear, if you have:

  data V a deriving Functor

David is proposing in #13117 [1] that the derived instance use
-XEmptyCase instead of the current error-based implementation:

  instance Functor V where
   fmap _ x = case x of {}

This seems fine and well, but given that #13117 is basically a
continuation of another discussion in #7401 [2], I feel like if we're
going to tackle the issue of derived instances for empty data
declaration, we should solve it for all stock classes.

In particular, there are two thorny issues to consider here. What if
we have this instead?

  data V2 deriving Eq

What instance should this produce? Reid Barton proposed in #10577 [3]
that it should be:

  instance Eq V2 where
    a == _ = case a of {}

But we have a choice here, since (==) has multiple arguments! The
definition could also conceivably be:

  instance Eq V2 where
    _ == b = case b of {}

Is there a uniform policy we can decide for functions with multiple
arguments like this? In fmap, it's unambiguous since there's only one
argument of type f a.

Another issue to consider is that if we adopted this convention for
derived Eq instances for empty datatypes, we'd actually be going
against the convention set for Data.Void. As noted in [4], this is the
current Eq instance for Void:

  instance Eq Void where
    _ == _ = True

I'm not proposing that we change this definition, since there are many
good reasons to have it this way (see the thread in [5] for Edward
Kmett's convincing argument in favor of the current Eq Void instance).
Rather, I'm asking if we would be OK with having this
discrepancy--that is, deriving Eq for your own Void2 type would
produce a different instance. Personally, I'd be fine with it, but I
think we should ask for the community's input as well.

So sorry to hijack this thread, David, but we really should answer
these two questions as well:

1. What do we do in ambiguous cases like derived (==) implementations
for empty datatypes?
2. Are we fine with derived instances for empty datatypes sometimes
being different than the corresponding instances for Data.Void?

Ryan S.
-----
[1] https://ghc.haskell.org/trac/ghc/ticket/13117
[2] https://ghc.haskell.org/trac/ghc/ticket/7401#comment:46
[3] https://ghc.haskell.org/trac/ghc/ticket/10577
[4] https://mail.haskell.org/pipermail/libraries/2015-July/025959.html
[5] https://mail.haskell.org/pipermail/libraries/2015-July/025965.html


More information about the Libraries mailing list