I discovered an interesting issue when attempting to implement monoids, groups, and rings in Scala. As described in these threads (Generic matrix multiplication using typeclasses and Abstract algebra in Scala ) I used a technique based on typeclasses, even if it is unclear whether such qualifies as a typeclass, perhaps better described as a strategy pattern.
Anyway the issue is this. A ring is a set with two operators, typically called +
and *
. The set is a group (Abilene) with respect to +
and the same set is a monoid with respect to *
. So one way to implement a ring, is to first implement the additive group and the multiplicitve monoid, and then compose them by delegation. This is not a problem mathematically, but does present an interesting code partitioning problem. In particular sometimes the implementation is clearer if we implement multiplication in terms of addition. Here is an example.
The ring of polynomials: We can add and subtract mathematical polynomials. So it is easy to implement the additive group of polynomials in Scala.
We can multiply but not divide polynomials (i.e., when you divide two polynomials you might not get another polynomial), so mathematically polynomials are a monoid.
However, if I try to implement the multiplicitive monoid, I have a problem. The straightforward algorithm for multiplying polynomials such as (ax^2 + bx + c) * (fx^2 + gx + h)
is to use the distributive law and compute (afx^4 + agx^3 + agx^)
, then (bfx^2 + bgx^2 + bhx)
, and finally (cfx^2 + cgx + ch)
. Now I have 3 polynomials that I want to add, for example with foldLeft
. But wait, the multiplicitive monoid does not know how to add polynomials. To add two polynomials, I need the additive-group object. (truthfully, I don’t really need the additive-group inverse, just the add
and the zero
to construct the foldLeft
call.)
Of course I can write an add
within the curly braces of the polynomial-multiplicitive-monoid
class. But them I’m duplicating code simply to satisfy the language constraints. I could also write a self contained multiply function, which has the addition operation implicitly built into it (sort of a convolution operation), but that will be more obscure. The gut feel is, I’ve already written an add function; just call it.
What is interesting is that this problem is not at all apparent mathematically, but becomes apparent when trying to code it up.