Skip to content

Sum Natural is not a lawful Group instance. #16

@jonathanknowles

Description

@jonathanknowles

Hi there!

First of all, thank you for creating and maintaining this library—I really appreciate the work that has gone into it!

While experimenting, I happened to notice that Sum Natural is an instance of Group, which caught me by surprise. Since the natural numbers under addition don’t form a group, I was curious about the reasoning behind this instance.

Looking at the laws stated in this library, the law a <> invert a == mempty doesn’t hold for any non-zero value of Sum Natural, since applying invert to a non-zero value results in an arithmetic underflow exception. That behaviour is understandable given that, for historical reasons, base defines Natural as an instance of Num, and that the Group instance for Sum a is currently defined as:

instance Num a => Group (Sum a) where
  invert = Sum . negate . getSum

One could argue that the decision (presumably made long ago!) to make Natural an instance of Num was questionable, since this means the Num laws can’t always be strictly relied upon. Though given the mathematical focus of the groups library, I wonder whether maintaining this behaviour is the best approach?

Some other libraries have made a choice to avoid relying on the customary Num laws always holding. For example, in monoid-subclasses, Sum Natural is an instance of PositiveMonoid, but Sum Integer is not.

Perhaps a similar approach could be taken here? I suppose that one solution might be to introduce a helper class, such as:

class Num a => SumGroup a

instance SumGroup Int
instance SumGroup Int8
instance SumGroup Int16
instance SumGroup Int32
instance SumGroup Int64
instance SumGroup Integer
...

Then, the constraints for the Group instance of Sum a could be strengthened:

instance SumGroup a => Group (Sum a)

This would have the advantage of allowing types to be added on a case-by-case basis (and giving downstream users the flexibility to take the same measured approach for their own types). The downside, of course, is that making this change would require some caution to avoid breaking existing code.

I’d love to hear your thoughts on this. Thanks again for all your work on this library.

Best regards,
Jonathan

Metadata

Metadata

Assignees

No one assigned

    Labels

    wontfixThis will not be worked on

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions