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.
Pingback: Enfranchised Mind » How Should I Burn My Free Time?