On monoids and metaphor shear

So, the other night, when I was tired of coding, I posted a collection of thoughts I’ve had on Haskell. They included some deep thoughts (such as the relationship between Haskell and Lisp), some real problems (the module system), some problems that aren’t as big a deal people make them out to be (space leaks). In addition, I threw in one thought that was one small step above being a cheap shot. “It’s derivative”, I thought, “SPJ has said basically the same thing.” Then I thought “oh, what the hey. This article could use a couple of chuckles anyways, even cheap ones. Everyone will simply read that, maybe chuckle, and pass on.” So in it went. What can I say, it was late and I was tired.

Guess which comment caused all the hubbub.

Not only did the original post make reddit, but the long discussion about the post on Haskell-cafe, and at least one rebuttal also made it to reddit. This post started life as a response to that original post, but in writing it, I discovered there is something interesting to say here, so it got changed into it’s own article.

The first thing I want to disabuse people of is where the term “monoid” comes from. Now, I’m not a mathematician, but I’ve actually read up some on Abstract Algebra (back during my cryptography phase), and the term didn’t ring a bell. Just to check, I pulled down my Abstract Algebra book (which is the second edition of this book, which I see now has a third edition), and checked it. It doesn’t mention monoids anywhere- at least according to both the table of contents and the index. The abstract algebra name for a thing with an operator and an identity element is group, not monoid (although, to be fair, group also implies that the operator is associative and that every element has an inverse.

The point here is not that “monoid” should have been called “group” (it shouldn’t have been), the point here is that the term monoid didn’t come from abstract algebra. The term might have snuck into abstract algebra, but you can be tolerably familiar with abstract algebra and still not know about “monoids”. Yes, this is on the basis of one book- but remember that most mathematicians haven’t read more than about one book on abstract algebra, and most programmers haven’t even read that many.

The second point I’d like to make is that the Haskell concept of a monoid and the mathematical concept of a monoid are different concepts. I’ll take just one example- in mathematics, integers are monoids twice over, once over addition (with 0 as the identity element), and once over multiplication (with 1 as the identity element). Due to various reasons, in Haskell, you can only give each type one definition of a given type class, such as Monoid. So Integers are only allowed to be Monoids in one, not two (or more) ways. The category theory has just encountered what is called “metaphor shear”.

I’m tempted at this point to say something like “if you don’t know what metaphor shear is, and aren’t willing to look it up, screw you, you lazy bastard.” This is, in essence, the attitude taken by a number of respondents to my post. I want you to consider, for a moment, what your response would be if I had taken that position. It’d probably be something like “Screw me? Screw him! I don’t have to read his stupid blog anyways. He probably doesn’t have anything worth listening to anyways!” It is my job, as a writer, to convince you the reader that I have something interesting to say, and coping and attitude doesn’t help that.

So what is metaphor shear, you ask? I’m glad you brought that up. Metaphor shear is the term defined by Neal Stephenson in his great, and greatly under-appreciated (IMHO) “In the Beginning was the Command Line”, which is both available online and book form. The basic idea is that most of our interactions with computers are done via metaphors. We had documents and files and folders and spread sheets long before we had computers, when computers entered the picture they adopted the existing concepts as metaphors. What the word “folder” meant when applied to computers was similar to, but subtly different from, what it meant to the pre-computer office worker. However, occasionally the underlying reality pokes through, in unexpected and often unpleasant ways. For example, Stephenson describes the experience the first time he upgraded his word processor and discovered that all his old documents were suddenly illegible, thusly:

It was–if you’ll pardon me for a moment’s strange little fantasy–as if I’d gone to stay at some resort, some exquisitely designed and art-directed hotel, placing myself in the hands of past masters of the Sensorial Interface, and had sat down in my room and written a story in ballpoint pen on a yellow legal pad, and when I returned from dinner, discovered that the maid had taken my work away and left behind in its place a quill pen and a stack of fine parchment–explaining that the room looked ever so much finer this way, and it was all part of a routine upgrade. But written on these sheets of paper, in flawless penmanship, were long sequences of words chosen at random from the dictionary.

As a programmer, I was deeply familiar with the experience of metaphor shear, even long before I read Stephenson’s book and learned what the term was. We programmers tend to call our metaphors “abstractions”, but a rose by any other name, you quickly learn, still has thorns. This is the difference between programming and mathematics- you don’t have leaky abstractions in mathematics. You don’t get silly limits, like you can only have one monoid per type. In mathematics, working with integers that have, say, 1021 decimal digits is no harder than working with numbers with only 1 decimal digit, in programming, there is a huge difference- in the former case, you hit that pesky memory limitation thing. Any programmer who’s been around a bit has similar stories to tell- for example, C++, Java, Perl, and Ruby all have “objects”, but all mean subtly (or not so subtly) different things by that word.

We have learned to hold our abstractions loosely, and try to not assume too much. The agile programmers have even codified this. They all say “Don’t assume, test!” By which they mean that if your code does depend upon some specific behavior, especially of an abstraction, to explicitly write unit tests to prove (in the scientific, not mathematical, sense) that the abstraction does, in fact, work that way. Because every programmer of any experience has a whole pile of stories where the documentation claimed something was true in all cases, where there were cases it was not true, or even that it wasn’t true in any cases at all. We assume, from long experience, that all abstractions will shear.

Object orientation, in my opinion, is just one huge exercise in metaphor shear. The proponents of OO claim that one of the reasons it is superior is that it reflect (read: it is a metaphor for) things in real life (i.e. everything not programming). The menu is not the meal, the map is not the territory, and the class is not the thing in real life it represents. Which leads to all sorts of amusing and instructive instances of metaphor shear.

This, then, is the real advantage of “appendable” as a name over “monoid”- precisely because it is the less precise name. Although maybe not “appendable”, maybe I should have said “addable”- after all, as programmers we are used to both adding integers and adding elements to containers. But it’s not how “newbie friendly” the name is. Maybe Real World Haskell could have saved a page explaining what a Monoid was, had it been named “Addable” or “Appendable” instead. And considering how much violence Haskell does to the average programmer’s understanding of the “class”, “function”, and “variable” metaphors, I don’t think that any significant number of programmers have been turned away by the name “monoid”

This is one of the big advantages I think Haskell has- it is one of the least abstract languages there is. What the heck do I mean, least abstract? Well, consider what the reality of what we programmers are doing. When a Java programmer says, for example, “in this code I have an object of class Point”, it doesn’t mean he has the Euclidean ideal concept of a point, and it doesn’t mean there is an actual physical location, it means the code has a computational object which has certain computational operations defined upon it.

Functional programming languages like Haskell and Ocaml keep the underlying reality, the underlying computation, close to the surface, in the form of the programmatic version of the Lambda calculus. It’s not that there isn’t abstraction and metaphor involved here, it’s just much easier to see the reality of the computational processes underlying the jungle of leaky metaphors.

And the less you think you’re working with something you’re not- be it gritty-reality things like cars or mathematical platonic ideals like points or monoids, the less likely you are going to be surprised when the reality peaks through.

No related posts.

This entry was posted in Classic, Programming Language Punditry. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.
  • Brian

    There is one comment I wanted to make but didn’t manage to work in, and that is this: this is why, as programmers, it’s important to understand the things we’re working with. Why it’s important to understand data structures and operating systems and compilers and all the other things we work with, even if we’re not implementing them. Abstractions are leaky and metaphors shear, and knowing how something is implemented informs you as to how the abstraction is likely to leak or metaphor to shear- and how to deal with it when it does. We may all bitch and complain about how it shouldn’t ought to be like this, but it is, and this isn’t likely to change.

    Occasionally you can even get metaphor shear to work for you.

  • http://procrastiblog.com Chris Conway

    Brian, there seems to be an elision here:

    Just to check, I pulled down my Abstract Algebra book (which is the second edition of available online and book form. The basic idea is that most of our interactions with computers are done via metaphors.

  • Brian

    Yes. A fairly serious one- three and a half paragraphs. Someone forgot a closing quote. Try it now.

  • http://james-iry.blogspot.com James Iry

    Monoids have no requirement to be invertible. A group is a monoid that is invertible. The integers form a group with addition and negation. But there is no inverse for lists so list/concatenation form a monoid but not a group. I’m sorry your textbook doesn’t have monoids, but they’re a well understood and useful concept in both abstract algebra and programming.

  • Mikhail Glushenkov

    > in mathematics, integers are monoids twice over,

    Yes, this is why Data.Monoid has two Num wrappers: Sum and Product.

  • http://surrealization.blogspot.com Mitch

    I agreed with most of your last post and most of this one, so I’m surprised to hear that it was controversial. It may seem more controversial than it really was, given that often people only comment when they disagree.

    Re: names–I agree that in programming it’s important to give things descriptive names. When you’re reading code and you see an identifier that does a good job of describing the thing it identifies, that narrows the possibilities down for you as a reader. That’s a good thing most of the time. If I were reading someone’s code and I saw a variable named “a”, I’d get annoyed because I’d think, “ugh, that could refer to anything”. Having to keep that huge range of possibilities in mind makes it harder for me to grok the code.

    But in math, especially with something very abstract like a monoid, you want the range of possibilities to be as broad as possible. That wide range of possibilities is the entire reason for abstraction in mathematics; in math you want to be able to apply your mathematical machinery to as many different things as you can. So it’s hard to choose good descriptive names for things, since you want people to try and cram all kinds of weird stuff into your abstraction–that’s what gives it power. Narrowing the range of things that people might think about your abstraction is probably counterproductive.

    That’s exactly the difficulty you faced over whether “monoid” should be “addable” or “appendable”.

    Or maybe it is possible, if we choose words that are general enough. Perhaps the generality of the mathematical abstraction could be conveyed by the generality of the word chosen to name it. “combinable”, maybe?

  • http://surrealization.blogspot.com Mitch

    For “monad”, maybe “container”?

  • http://gimbo.org.uk/ Andy Gimblett

    Just a heads-up: the first link in the article is identical to the second, and judging by its context, it shouldn’t be.

  • Fritz

    Well, I remember hearing the term monoid long ago in the context of abstract algebra, but the best I can find without a library (i.e., with just a few minutes of on-line searching) suggests that the term was used in at least one algebra textbook in 1951. But based on your own abstract algebra book, it appears that it hasn’t been widely used until recently (and perhaps more so in the computer side of math).

    But in any case, I wouldn’t let people get to you too much with snarky comments about algebra and its terminology. Yes, groups are distinct from monoids, and monads, etc., but you make a valid point (in the previous post), namely that people who aren’t familiar with math terminology will be put off a bit by these names. On the other hand, it’s very hard to pick good, pithy terms that suggest the very abstract meanings intended in set theory and abstract algebra. The good ones get taken up pretty quickly (and sometimes aren’t even all that suggestive): set, collection, group, field, category for that matter.

    The fact is, basic Haskell is pretty straightforward, in that it is more like high school algebra than imperative programming, for example. But the more you get into it (higher-order functions, type classes, etc.), the more it helps to have either some background in math or at least a predisposition to a mathematical style of thought. And a lot of this involves semantic/pragmatic issues rather than just vocabulary.

    Anyway, your point about type classes being instantiable by types only once (at a time) is a big issue, I think: it really impedes the view of type classes as being essentially abstract algebras, as you point out. (The other big one is formalizing and enforcing the axioms, but that requires a much stronger type theory, and much more work from the programmer.) I think there have been proposals that would address the “multiple instantiability” issue, probably in the Haskell’ (prime) “literature”.

  • jag

    Brian, the first link, “thoughts I’ve had on Haskell”, links to the SPJ paper, not to your blog entry.

  • Robin Green

    You may have missed the responses to your original post that talked about this – there were, after all, a hell of a lot of responses – but the key point is, Appendable does *not* correspond to all the possible valid monoids you can have in Haskell, so Appendable is *not* an accurate name. Worse than a slightly leaky abstraction is an abstraction which doesn’t even encompass all the possible meanings it is supposed to cover.

    At a stretch, prepending can be seen as “appending in reverse” (technically it’s the dual monoid of the appending one), but multiplication, for example – which is an example you used in this very post! – is not a kind of appending, AFAICS. Nor is set union.

    You mention unit tests. What we have for Monoid in Haskell is the two mathematical monoid laws – those are valid assumptions. Yes, absolutely there should be QuickCheck (or similar) tests for every Monoid that test the monoid laws, and sometimes there aren’t, but you can’t use the unit test argument to argue that we should have less descriptive names for things(?!)

  • michael

    Minor nit here, But I would be careful generalizing that the origin of “monoid” is not from Abstract Algebra by virtue of not being addressed in Dummit & Foote. Had you chosen Jacobsen, you would have been hit in the face with it.

    There is an interesting parallel to your main point in the world of Graduate Algebra textbooks. D&M was my first grad algebra book as well, but it is always useful to have other viewpoints on the same subject. Thus one usually has other algebra books like Herstein or Jacobsen or Artin or (shudder) Hungerford. But worst of all (from my point of view) was Lang’s book, due to the fact that he decided to call things by different names, making it infuriatingly useless as a cross reference.

  • Tracy Harms

    The first link does not point where you intended. It is labelled “thoughts I’ve had on Haskell”

  • http://comonad.com/ Edward Kmett

    Actually a Group is a Monoid with an inverse. A Monoid is a weaker concept.

    It is not surprising that an introductory text on abstract algebra neglected to include the concept.

    Abstract algebra historically was born of the discovery of fields by trying to abstract out what made the Real numbers tick. From there, it was discovered you can remove, say the rule of multiplicative inverse and get Rings or even the whole concept of multiplication or addition to get down to a Group.

    However, you can remove more rules still.

    Another approach to teaching abstract algebra works from the ground up.

    You start with a single binary operation called a Magma, and you add rules to it. You can add associativity and an identity and get a Monoid, then add an inverse to get a Group.

    http://en.wikipedia.org/wiki/Magma_(algebra)

    The reason your book didn’t cover Monoids is an issue of pedagogy, not origin. Often texts that are first introducing abstract algebra want to start with a structure that has enough rules to be interesting. The entry point most people choose is a Group. Mainly because once you have a group there are all sorts of non-trivial things you can prove about the nature of finite groups, generators, etc.

    Another introductory textbook might very well choose to start with a semigroup, which is an associative magma or a monoid without a unit. It is all a matter of whether the person presenting the material likes to work up by adding rules and structure or down by removing rules and structure and seeing what still works.

    Now, Haskell typeclasses *do* tend to force the choice of a single canonical implementation. This breaks down with Monoids when it comes to, say, instances of Num.

    This is why Haskell uses newtype wrappers to disambiguate meaning. where other languages like ML would require you to explicitly open an appropriate module, in Haskell you wrap the value in a newtype wrapper. The newtypes in Data.Monoid let you work with a Sum or Product or Max of Integers, opening back all of your options, yet leaving you with a hopefully sensible default.

    In general when faced with an ambiguous choice of what a typeclass should implement, don’t implement it directly on the type, define newtype wrappers for the type and define it on those. This is how Haskell works around its lack of an ML-style module system. In exchange it can get away with much more terse code for the remaining 95% of the cases it encounters.

  • Pingback: Enfranchised Mind » How Should I Burn My Free Time?

  • Categories