The reasoning why sum types have no Storable instance by default is that the encoding would be quite arbitrary. In your example: Why are the tags 8 bit wide, and why are the tag values 0 and 1? Do we need a tag at all? For e.g. Maybe (Ptr a) a more common encoding is to have no tag at all and represent Nothing as a null pointer. For product types things are less arbitrary, but even then there is the issue of alignment. If you need serialization, you can use Data.Binary.
I think we should close this ticket as wontfix, because the lack of these instances was a very deliberate decision.
How is this an argument against adding the encodings? If they function correctly, why does it matter that they aren't "fixed" in some sense?
Why are the tags 8 bit wide, and why are the tag values 0 and 1?
Because it makes sense and works. Why, for a Ratio, is the numerator stored before the denominator? Presumably for the same reason. The choice of representation doesn't really matter a whole lot; the point of this feature request isn't to bikeshed over the exact implementation, but to establish if there's some fundamental stumbling block with this approach.
then there is the issue of alignment
I *think* my lcm trick solves this for sum types. For product types, there are some obvious approaches.
If you need serialization, you can use Data.Binary.
Besides Data.Binary being vastly slower than Storable, the primary use case here is Data.Vector.Storable and Data.Array.Storable. You can't write an Unbox instance for Maybe a, but you can (as I've done here) write a Storable instance.
How is this an argument against adding the encodings? If they function correctly, why does it matter that they aren't "fixed" in some sense?
The general rule of thumb is: The Prelude doesn't make arbitrary choices when there is no obviously "right" way of doing things. Well, there are exceptions, but that's the idea. In our case, there are various arbitrary choices.
Remember that the prime motivation for Storable is the FFI, and there are numerous ways used in actual C libraries to encode the equivalent of Maybe or Either, and none of them is "more correct" than the other.
Why are the tags 8 bit wide, and why are the tag values 0 and 1?
Because it makes sense and works.
CChar or CInt or Word make sense, too, and depending on the circumstances, they would be even better. That was just an example for the arbitrary decisions which would have to be made.
[...]
If you need serialization, you can use Data.Binary.
Besides Data.Binary being vastly slower than Storable, the primary use case here is Data.Vector.Storable and Data.Array.Storable. You can't write an Unbox instance for Maybe a, but you can (as I've done here) write a Storable instance.
If you directly want to use Maybe and Either with those containers, nothing is going to stop you from rolling your own. A better approach would probably be newtype wrappers for Maybe and Either with the corresponding Storable instances, making your arbitrary decisions explicit.
Is using Binary really that much slower than your own code?
Remember that the prime motivation for Storable is the FFI
That's a fair argument. But I'm curious; how often do people use the various Storable array types? I use Data.Vector.Storable a fair amount, and if that's a common use case, it makes sense to support it as well.
nothing is going to stop you from rolling your own
Which is precisely what I've done here, although I think it could make sense to use a standardized, agreed-upon representation known to be alignment-safe and have good performance.
That said, I think you're right that this would be equally well-served by a library external to base, so on that note I'll close the ticket.