RFC for a change in EmptyDataDecls instance deriving

# 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-182000... [2]: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/data-type-ex... [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

1) I think an empty case is nicer than the current error calls, since
it gives the (hopefully more informative) error from the point where
the empty data type was generated, instead of a generic error from the
instance. I've used similar instance definitions here [1].
2) It makes sense to me to also allow non-standalone deriving, and if
that is allowed, it should be the same as standalone deriving. Doing
anything else would be very confusing.
3) I have no idea. What's the rationale behind returning True when
comparing two Voids?
Erik
[1] https://github.com/silkapp/rest/blob/60faa55887fbf7332dc7aa82a9505e2d92f7c31...
On Wed, Jul 15, 2015 at 5:56 PM, Ömer Sinan Ağacan
# 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-182000... [2]: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/data-type-ex... [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 _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

2015-07-15 19:55 GMT+02:00 Erik Hesselink
[..] 3) I have no idea. What's the rationale behind returning True when comparing two Voids? [...]
Hmmm, what's the rationale of throwing an exception? I can imagine True, False, throwing an exception etc., but I can't see a reason why one should be "better" or "more natural" than the other.

It's all a bit weird. I think the Proxy instance is lazy too. I would tend
to think that empty types shouldn't have these instances, and that if they
do that should be strict (empty case), but I can't prove that's the right
way.
On Jul 15, 2015 5:53 PM, "Sven Panne"
2015-07-15 19:55 GMT+02:00 Erik Hesselink
: [..] 3) I have no idea. What's the rationale behind returning True when comparing two Voids? [...]
Hmmm, what's the rationale of throwing an exception? I can imagine True, False, throwing an exception etc., but I can't see a reason why one should be "better" or "more natural" than the other.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On 2015-07-16 at 05:28:03 +0200, David Feuer wrote:
It's all a bit weird. I think the Proxy instance is lazy too. I would tend to think that empty types shouldn't have these instances, and that if they do that should be strict (empty case), but I can't prove that's the right way.
Btw, something similiar came up for deepseq, regarding NFData instances for types only inhabited by ⊥ (and the issue of H2010 forbidding instance auto-derivation for constructor-less types was mentioned too): https://github.com/haskell/deepseq/pull/1#issuecomment-61914093 -- hvr

I'd caution against randomly changing Eq and Ord for Void to be less
defined in the ill-considered name of consistency.
We rather deliberately made them as "defined as possible" back in 2012
after a very long discussion in which the pendulum swung the other way
using a few examples where folks tied knots with fixed points to get
inhabitants of Void and it was less consistent to rule them out than it was
to define equality on _|_ to be True.
I'd challenge that nothing is gained by making these combinators strict in
their arguments.
-Edward
On Thu, Jul 16, 2015 at 7:14 AM, Herbert Valerio Riedel
It's all a bit weird. I think the Proxy instance is lazy too. I would tend to think that empty types shouldn't have these instances, and that if
On 2015-07-16 at 05:28:03 +0200, David Feuer wrote: they
do that should be strict (empty case), but I can't prove that's the right way.
Btw, something similiar came up for deepseq, regarding NFData instances for types only inhabited by ⊥ (and the issue of H2010 forbidding instance auto-derivation for constructor-less types was mentioned too):
https://github.com/haskell/deepseq/pull/1#issuecomment-61914093
-- hvr

The Proxy instance for Eq and Ord is deliberately lazy for the same sort of
reason.
It is, simply, the maximally defined version of the function and, like it
or not, folks with good intentions but bad design sense often still pass
undefineds for Proxy arguments when they are used to older APIs that didn't
take proxies.
The lazy version of each of these when inlined can eliminate whole code
paths that would otherwise be compiled.
-Edward
On Thu, Jul 16, 2015 at 8:29 AM, Edward Kmett
I'd caution against randomly changing Eq and Ord for Void to be less defined in the ill-considered name of consistency.
We rather deliberately made them as "defined as possible" back in 2012 after a very long discussion in which the pendulum swung the other way using a few examples where folks tied knots with fixed points to get inhabitants of Void and it was less consistent to rule them out than it was to define equality on _|_ to be True.
I'd challenge that nothing is gained by making these combinators strict in their arguments.
-Edward
On Thu, Jul 16, 2015 at 7:14 AM, Herbert Valerio Riedel
wrote: It's all a bit weird. I think the Proxy instance is lazy too. I would tend to think that empty types shouldn't have these instances, and that if
On 2015-07-16 at 05:28:03 +0200, David Feuer wrote: they
do that should be strict (empty case), but I can't prove that's the right way.
Btw, something similiar came up for deepseq, regarding NFData instances for types only inhabited by ⊥ (and the issue of H2010 forbidding instance auto-derivation for constructor-less types was mentioned too):
https://github.com/haskell/deepseq/pull/1#issuecomment-61914093
-- hvr

I still don't understand why these instances exist, except maybe to write
(Proxy :: Proxy p)==(Proxy :: Proxy q) instead of the more usual [Proxy ::
Proxy p, Proxy :: Proxy q] to force p~q. I'll admit it looks pretty, but it
seems a bit silly. The Void instance doesn't even have this dubious benefit.
Why would one ever want to tie a knot in Void? That violates the entire
purpose of the type--communicating the idea that it's not supposed to be
inhabited (btw, I think there is a sensible argument for making Await in
machines strict in its request argument so that a SourceT is truly
incapable of awaiting; I don't know how that would affect efficiency
though).
The efficiency argument only makes sense if one accepts that the code in
question is sane to begin with. If someone writes disgusting code, I don't
care if it's compiled well.
On Jul 16, 2015 8:29 AM, "Edward Kmett"
I'd caution against randomly changing Eq and Ord for Void to be less defined in the ill-considered name of consistency.
We rather deliberately made them as "defined as possible" back in 2012 after a very long discussion in which the pendulum swung the other way using a few examples where folks tied knots with fixed points to get inhabitants of Void and it was less consistent to rule them out than it was to define equality on _|_ to be True.
I'd challenge that nothing is gained by making these combinators strict in their arguments.
-Edward
On Thu, Jul 16, 2015 at 7:14 AM, Herbert Valerio Riedel
wrote: It's all a bit weird. I think the Proxy instance is lazy too. I would tend to think that empty types shouldn't have these instances, and that if
On 2015-07-16 at 05:28:03 +0200, David Feuer wrote: they
do that should be strict (empty case), but I can't prove that's the right way.
Btw, something similiar came up for deepseq, regarding NFData instances for types only inhabited by ⊥ (and the issue of H2010 forbidding instance auto-derivation for constructor-less types was mentioned too):
https://github.com/haskell/deepseq/pull/1#issuecomment-61914093
-- hvr

The Eq Void instance is very useful for structures with a type
parameter instantiated to Void. You might still want to compare these
for equality, but that needs an Eq instance for Void.
Erik
On Thu, Jul 16, 2015 at 3:10 PM, David Feuer
I still don't understand why these instances exist, except maybe to write (Proxy :: Proxy p)==(Proxy :: Proxy q) instead of the more usual [Proxy :: Proxy p, Proxy :: Proxy q] to force p~q. I'll admit it looks pretty, but it seems a bit silly. The Void instance doesn't even have this dubious benefit.
Why would one ever want to tie a knot in Void? That violates the entire purpose of the type--communicating the idea that it's not supposed to be inhabited (btw, I think there is a sensible argument for making Await in machines strict in its request argument so that a SourceT is truly incapable of awaiting; I don't know how that would affect efficiency though).
The efficiency argument only makes sense if one accepts that the code in question is sane to begin with. If someone writes disgusting code, I don't care if it's compiled well.
On Jul 16, 2015 8:29 AM, "Edward Kmett"
wrote: I'd caution against randomly changing Eq and Ord for Void to be less defined in the ill-considered name of consistency.
We rather deliberately made them as "defined as possible" back in 2012 after a very long discussion in which the pendulum swung the other way using a few examples where folks tied knots with fixed points to get inhabitants of Void and it was less consistent to rule them out than it was to define equality on _|_ to be True.
I'd challenge that nothing is gained by making these combinators strict in their arguments.
-Edward
On Thu, Jul 16, 2015 at 7:14 AM, Herbert Valerio Riedel
wrote: On 2015-07-16 at 05:28:03 +0200, David Feuer wrote:
It's all a bit weird. I think the Proxy instance is lazy too. I would tend to think that empty types shouldn't have these instances, and that if they do that should be strict (empty case), but I can't prove that's the right way.
Btw, something similiar came up for deepseq, regarding NFData instances for types only inhabited by ⊥ (and the issue of H2010 forbidding instance auto-derivation for constructor-less types was mentioned too):
https://github.com/haskell/deepseq/pull/1#issuecomment-61914093
-- hvr
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

That makes sense.
On Jul 16, 2015 9:11 AM, "Erik Hesselink"
The Eq Void instance is very useful for structures with a type parameter instantiated to Void. You might still want to compare these for equality, but that needs an Eq instance for Void.
Erik
On Thu, Jul 16, 2015 at 3:10 PM, David Feuer
wrote: I still don't understand why these instances exist, except maybe to write (Proxy :: Proxy p)==(Proxy :: Proxy q) instead of the more usual [Proxy :: Proxy p, Proxy :: Proxy q] to force p~q. I'll admit it looks pretty, but it seems a bit silly. The Void instance doesn't even have this dubious benefit.
Why would one ever want to tie a knot in Void? That violates the entire purpose of the type--communicating the idea that it's not supposed to be inhabited (btw, I think there is a sensible argument for making Await in machines strict in its request argument so that a SourceT is truly incapable of awaiting; I don't know how that would affect efficiency though).
The efficiency argument only makes sense if one accepts that the code in question is sane to begin with. If someone writes disgusting code, I don't care if it's compiled well.
On Jul 16, 2015 8:29 AM, "Edward Kmett"
wrote: I'd caution against randomly changing Eq and Ord for Void to be less defined in the ill-considered name of consistency.
We rather deliberately made them as "defined as possible" back in 2012 after a very long discussion in which the pendulum swung the other way
using
a few examples where folks tied knots with fixed points to get inhabitants of Void and it was less consistent to rule them out than it was to define equality on _|_ to be True.
I'd challenge that nothing is gained by making these combinators strict in their arguments.
-Edward
On Thu, Jul 16, 2015 at 7:14 AM, Herbert Valerio Riedel
wrote: On 2015-07-16 at 05:28:03 +0200, David Feuer wrote:
It's all a bit weird. I think the Proxy instance is lazy too. I would tend to think that empty types shouldn't have these instances, and that if they do that should be strict (empty case), but I can't prove that's the right way.
Btw, something similiar came up for deepseq, regarding NFData instances for types only inhabited by ⊥ (and the issue of H2010 forbidding instance auto-derivation for constructor-less types was mentioned too):
https://github.com/haskell/deepseq/pull/1#issuecomment-61914093
-- hvr
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

The instances exist because people do things like
data Exp a
= Var a
| Lam (Exp (Maybe a)
| App (Exp a) (Exp a)
and manipulate "Exp Void" to represent a closed term all the time.
Being able to compare two closed "Exp" terms for equality is quite valuable
and that goes away if you remove these instances!
-Edward
On Thu, Jul 16, 2015 at 9:10 AM, David Feuer
I still don't understand why these instances exist, except maybe to write (Proxy :: Proxy p)==(Proxy :: Proxy q) instead of the more usual [Proxy :: Proxy p, Proxy :: Proxy q] to force p~q. I'll admit it looks pretty, but it seems a bit silly. The Void instance doesn't even have this dubious benefit.
Why would one ever want to tie a knot in Void? That violates the entire purpose of the type--communicating the idea that it's not supposed to be inhabited (btw, I think there is a sensible argument for making Await in machines strict in its request argument so that a SourceT is truly incapable of awaiting; I don't know how that would affect efficiency though).
The efficiency argument only makes sense if one accepts that the code in question is sane to begin with. If someone writes disgusting code, I don't care if it's compiled well. On Jul 16, 2015 8:29 AM, "Edward Kmett"
wrote: I'd caution against randomly changing Eq and Ord for Void to be less defined in the ill-considered name of consistency.
We rather deliberately made them as "defined as possible" back in 2012 after a very long discussion in which the pendulum swung the other way using a few examples where folks tied knots with fixed points to get inhabitants of Void and it was less consistent to rule them out than it was to define equality on _|_ to be True.
I'd challenge that nothing is gained by making these combinators strict in their arguments.
-Edward
On Thu, Jul 16, 2015 at 7:14 AM, Herbert Valerio Riedel
wrote: It's all a bit weird. I think the Proxy instance is lazy too. I would tend to think that empty types shouldn't have these instances, and that if
On 2015-07-16 at 05:28:03 +0200, David Feuer wrote: they
do that should be strict (empty case), but I can't prove that's the right way.
Btw, something similiar came up for deepseq, regarding NFData instances for types only inhabited by ⊥ (and the issue of H2010 forbidding instance auto-derivation for constructor-less types was mentioned too):
https://github.com/haskell/deepseq/pull/1#issuecomment-61914093
-- hvr

Do you have an example of things made possible by the version returning True?
Erik
On Thu, Jul 16, 2015 at 2:29 PM, Edward Kmett
I'd caution against randomly changing Eq and Ord for Void to be less defined in the ill-considered name of consistency.
We rather deliberately made them as "defined as possible" back in 2012 after a very long discussion in which the pendulum swung the other way using a few examples where folks tied knots with fixed points to get inhabitants of Void and it was less consistent to rule them out than it was to define equality on _|_ to be True.
I'd challenge that nothing is gained by making these combinators strict in their arguments.
-Edward
On Thu, Jul 16, 2015 at 7:14 AM, Herbert Valerio Riedel
wrote: On 2015-07-16 at 05:28:03 +0200, David Feuer wrote:
It's all a bit weird. I think the Proxy instance is lazy too. I would tend to think that empty types shouldn't have these instances, and that if they do that should be strict (empty case), but I can't prove that's the right way.
Btw, something similiar came up for deepseq, regarding NFData instances for types only inhabited by ⊥ (and the issue of H2010 forbidding instance auto-derivation for constructor-less types was mentioned too):
https://github.com/haskell/deepseq/pull/1#issuecomment-61914093
-- hvr
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Do you have an example of a thing made possible by making them more strict?
=)
-Edward
-Edward
On Thu, Jul 16, 2015 at 9:10 AM, Erik Hesselink
Do you have an example of things made possible by the version returning True?
Erik
On Thu, Jul 16, 2015 at 2:29 PM, Edward Kmett
wrote: I'd caution against randomly changing Eq and Ord for Void to be less defined in the ill-considered name of consistency.
We rather deliberately made them as "defined as possible" back in 2012 after a very long discussion in which the pendulum swung the other way using a few examples where folks tied knots with fixed points to get inhabitants of Void and it was less consistent to rule them out than it was to define equality on _|_ to be True.
I'd challenge that nothing is gained by making these combinators strict in their arguments.
-Edward
On Thu, Jul 16, 2015 at 7:14 AM, Herbert Valerio Riedel
wrote: On 2015-07-16 at 05:28:03 +0200, David Feuer wrote:
It's all a bit weird. I think the Proxy instance is lazy too. I would tend to think that empty types shouldn't have these instances, and that if they do that should be strict (empty case), but I can't prove that's the right way.
Btw, something similiar came up for deepseq, regarding NFData instances for types only inhabited by ⊥ (and the issue of H2010 forbidding instance auto-derivation for constructor-less types was mentioned too):
https://github.com/haskell/deepseq/pull/1#issuecomment-61914093
-- hvr
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Well, things made *im*possible: you can't do silly things like use
Voids as keys in a map, or look for Voids in a list, as that will
expose the Voids for the lies that they are. But you're right, I doubt
this is a very common use case. I guess it just feels wrong to me to
consider 'let x = x in x' be equal to 'error "boo"'. It also fits with
all other functions on Void, which, when receiving an argument, use
something like 'absurd' on it to produce their answer. Which leads to
another oddity: given 'v :: Void', if 'v == v = True', what about
something like 'absurd v :: Int == absurd v'? That would be bottom,
which again, seems weird to me.
Note that I have no great arguments and no intention of breaking
anyone's code, quite the opposite. So I'd be very interested to see
if/how defining the Void Eq instance to return True can be benificial.
Erik
On Thu, Jul 16, 2015 at 6:33 PM, Edward Kmett
Do you have an example of a thing made possible by making them more strict? =)
-Edward
-Edward
On Thu, Jul 16, 2015 at 9:10 AM, Erik Hesselink
wrote: Do you have an example of things made possible by the version returning True?
Erik
On Thu, Jul 16, 2015 at 2:29 PM, Edward Kmett
wrote: I'd caution against randomly changing Eq and Ord for Void to be less defined in the ill-considered name of consistency.
We rather deliberately made them as "defined as possible" back in 2012 after a very long discussion in which the pendulum swung the other way using a few examples where folks tied knots with fixed points to get inhabitants of Void and it was less consistent to rule them out than it was to define equality on _|_ to be True.
I'd challenge that nothing is gained by making these combinators strict in their arguments.
-Edward
On Thu, Jul 16, 2015 at 7:14 AM, Herbert Valerio Riedel
wrote: On 2015-07-16 at 05:28:03 +0200, David Feuer wrote:
It's all a bit weird. I think the Proxy instance is lazy too. I would tend to think that empty types shouldn't have these instances, and that if they do that should be strict (empty case), but I can't prove that's the right way.
Btw, something similiar came up for deepseq, regarding NFData instances for types only inhabited by ⊥ (and the issue of H2010 forbidding instance auto-derivation for constructor-less types was mentioned too):
https://github.com/haskell/deepseq/pull/1#issuecomment-61914093
-- hvr
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Voids as a key in a map blow up for different reasons, namely that Data.Map
evaluates the key.
In any event my experience tends to run to the opposite direction, anything
that makes code less defined, forces results that don't need to be forced
or passes dictionaries that don't get used is something I tend to worry
about as it leads to code that is doing make-work.
Your attempt at using x == y => f x == f y is compelling on the surface but
falls apart when you push on it.
x == y = True implies f x == f y = _|_ for tons of things, absurd isn't
terribly special in this regard.
() == () = True
repeat () == repeat () = _|_
There is a distinction between definitional equality (=) and constructive,
testable, equality (==).
What we really want is x = y implies f x = f y, which holds here. even x ==
y implies f x = f y, holds here, just not x == y implies f x == f y.
-Edward
On Thu, Jul 16, 2015 at 2:53 PM, Erik Hesselink
Well, things made *im*possible: you can't do silly things like use Voids as keys in a map, or look for Voids in a list, as that will expose the Voids for the lies that they are. But you're right, I doubt this is a very common use case. I guess it just feels wrong to me to consider 'let x = x in x' be equal to 'error "boo"'. It also fits with all other functions on Void, which, when receiving an argument, use something like 'absurd' on it to produce their answer. Which leads to another oddity: given 'v :: Void', if 'v == v = True', what about something like 'absurd v :: Int == absurd v'? That would be bottom, which again, seems weird to me.
Note that I have no great arguments and no intention of breaking anyone's code, quite the opposite. So I'd be very interested to see if/how defining the Void Eq instance to return True can be benificial.
Erik
On Thu, Jul 16, 2015 at 6:33 PM, Edward Kmett
wrote: Do you have an example of a thing made possible by making them more strict? =)
-Edward
-Edward
On Thu, Jul 16, 2015 at 9:10 AM, Erik Hesselink
wrote: Do you have an example of things made possible by the version returning True?
Erik
On Thu, Jul 16, 2015 at 2:29 PM, Edward Kmett
wrote: I'd caution against randomly changing Eq and Ord for Void to be less defined in the ill-considered name of consistency.
We rather deliberately made them as "defined as possible" back in 2012 after a very long discussion in which the pendulum swung the other way
using a
few examples where folks tied knots with fixed points to get inhabitants of Void and it was less consistent to rule them out than it was to define equality on _|_ to be True.
I'd challenge that nothing is gained by making these combinators strict in their arguments.
-Edward
On Thu, Jul 16, 2015 at 7:14 AM, Herbert Valerio Riedel
wrote: On 2015-07-16 at 05:28:03 +0200, David Feuer wrote:
It's all a bit weird. I think the Proxy instance is lazy too. I
would
tend to think that empty types shouldn't have these instances, and that if they do that should be strict (empty case), but I can't prove that's the right way.
Btw, something similiar came up for deepseq, regarding NFData instances for types only inhabited by ⊥ (and the issue of H2010 forbidding instance auto-derivation for constructor-less types was mentioned too):
https://github.com/haskell/deepseq/pull/1#issuecomment-61914093
-- hvr
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On 15/07/15 18:56, Ömer Sinan Ağacan wrote:
Haskell 2010 doesn't support data types without any constructors(aka. empty data type)[1].
Haskell 2010 does support data types without constructors: https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-690004....
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)?
The right question is whether the methods should be strict in the arguments of empty types. The strict version can be implemented with an empty case (which is stylistically nicer), or with error + seq/bang patterns; it doesn't matter. I agree that the derived methods should be strict.
2. Do you think with EmptyDataDecls and StandaloneDeriving, `deriving(..)` and standalone deriving should derive same instances?
Certainly.
3. Should we change instances of Void on the way, for consistency? (Ord and Eq especially)
Yes.
participants (7)
-
David Feuer
-
Edward Kmett
-
Erik Hesselink
-
Herbert Valerio Riedel
-
Roman Cheplyaka
-
Sven Panne
-
Ömer Sinan Ağacan