# Why does Ring support subtraction?

@derrickbeining asked some good questions about the `Ring` type class on Slack and I think they deserve a response here.

Can someone explain why `Data.Ring` supports subtraction? From the little bit of googling I’ve done, I don’t see any definitions of Rings that say anything about subtraction.

As you’ve probably found, definitions of rings don’t usually mention subtraction specifically, they usually talk about additive inverses instead. That is, there’s an function `negate :: a -> a` with the property that for all `a`, we have `a + negate a = zero`. Given a `negate` function, there is only really one sensible choice for defining subtraction: `a - b` would be defined as `a + negate b`. So I would say that subtraction is essential to rings, it’s just that this is not immediately obvious from the definition.

PureScript has opted to put it the other way around: instead of having `negate` be part of the definition of the class and defining `sub` in terms of `negate`, we put `sub` inside the class, since it’s generally the one we care more about anyway, and define `negate` as `\a -> zero - a`.

The laws given for the PureScript `Ring` class are then an attempt to describe the same mathematical structure, given that we are taking `sub` as part of the definition rather than `negate`. (In the process of writing this out I am coming to think it hasn’t quite been successful; I think our `Ring` class is a bit weaker than the real definition of a ring. However, this post is long enough already, so I’m going to continue this thought elsewhere.)

Also, the definition of the additive inverse law in the docs is described as `a - a = (zero - a) + a = zero` , does this mean `Ring` can’t be properly implemented for unsigned integers that don’t support overflow (just throws instead)?

Correct. An unsigned integer type which doesn’t support overflow is definitely not a ring, because in a ring, every element needs to have an additive inverse such that if you add an element and its additive inverse together, you get zero.

Is the `(zero - a) + a = zero` bit actually necessary? Everywhere else online I’ve seen defines the additive inverse only as `a + (−a) = 0`

With the approach we are taking, yes. For example: suppose I have a type in PureScript which can represent all of the nonnegative integers, with the normal `Semiring` instance. If we only require that `a - a = zero`, then I can define subtraction as, say, `\x y -> if x == y then zero else x`, or even as `\_ _ -> zero`. Both of these satisfy `a - a = zero`, but neither gives you a valid subtraction operation.

2 Likes

I created an issue for the issue of our current `Ring` laws being too weak here: https://github.com/purescript/purescript-prelude/issues/212

1 Like