
Stephen Tetley wrote:
Semigroups seem a lot less useful than monoids. They might be more ubiquitous, but there seems to be less you can do with them
My experience has not been so. For me they are extremely useful, and come up all the time. Here are some concrete examples: The fundamental example of a semigroup is a non-empty list, which comes up all the time. Besides that, many of the "monoids" that come up are really semigroups. One tends to force them to be monoids by artificially adjoining an abstract unit element, resulting in superfluous Maybe wrappers, unsafe pattern matches, convoluted and harder-to-read code, etc. Here is another example that I had, much less trivial: in a large image-recognition application I wrote, there is a type representing graphical objects recognized on the canvas. Each object has its rectangular bounding box as one of its properties. The objects combine to form more and more complex objects as higher-order structure is recognized. There is no natural unit element - even an empty bounding box must exist at some specific location on the canvas. So this is really a semigroup, not a monoid. A vast improvement to my code resulted from porting it from Monoid to Semigroup.
e.g. sconcat in the Semigroup class is quite convoluted to avoid emptiness
It avoids emptiness once, rather than you doing it over and over again in your own code. I don't think that's convoluted at all.
a Writer-like thing without zero would be very strange (presumably it would actually have to be a state monad?).
No. The run function would start with a seed, or a non-empty list, or some other non-empty type. That would be natural, since those are exactly the cases in which you would use it. Thanks, Yitz