Implement NonEmpty as a newtype
At MuiHac today I had a discussion about NonEmpty, and we wondered if it would be beneficial to implement NonEmpty
as
newtype NonEmpty a = NonEmpty [a]
with :|
being a pattern synonym (a COMPLETE
and associated one, so the change would be invisible to users), and NonEmpty
not being exported, of course, to preserve the invariant in the Data.List.NonEmpty
module.
The benefits would be less code (a few functions can be just coerce
’d versions of the normal list functions), and allocation-free conversion to and from lists. And it would show off the ability to use pattern synonyms to transparently change the implementation.
I briefly had a look if that’s possible, but it’s not as simple as I thought:
The type is defined in GHC.Base
, not in Data.List.NonEmpty
, so we couldn’t actually hide the NonEmpty
constructor completely, making this change quite a bit less appealing. But it’s in GHC.Base
for a good reason (it’s used in the definition of the Semigroup
class). I don’t see a good way around that (without using .hs-boot
files, at least).
I’m writing this issue in the hope it can be found if someone else wonders “why is NonEmpty
not a newtype”.
It also points to a deeper problems in Haskell: water-tight abstraction with newtypes with hidden constructors is only possible if all “priviledged” code is within a single module; I can’t easily safely allow some other modules to access the constructors, but not all.