A monoid for server parties
Happstack is a Haskell web applications framework. I hadn't played with it in a while but Happstack 0.5.0 was recently released so I decided to try it out. You can get it with cabal:
$ cabal update $ cabal install happstack
Happstack has a pretty detailed tutorial, which is actually a
self-hosted happstack site that you can cabal install
and dig around in. It takes a while though, so let's just get
into it. The tutorial doesn't actually start showing
any code until section 7,
shot at happstack. This shows you how to run a Hello World
server from Haskell's
$ ghci Prelude> import Happstack.Server Prelude Happstack.Server> simpleHTTP (Conf 8080 Nothing) (return "Hello World!")
Then your http://localhost:8080/ should show a Hello World message, ie. you can run this in another terminal:
$ curl -i http://localhost:8080/ HTTP/1.1 200 OK Connection: Keep-Alive Content-Length: 12 Content-Type: text/plain; charset=UTF-8 Date: Tue, 04 May 2010 01:02:31 GMT Server: Happstack/0.5.0 Hello World!
A REPL is great for playing around, but some real code to read for an example server is ControllerBasic.hs.
At the top of that file we get hit with this:
mzero corresponds to a 404 and mzero `mappend` f = f, while if f is not mzero then f `mappend` g = f.
That's not even code, it's a
It's talking about a type called ServerPartT, which you can think of as an abstract part of your web server, like the part that handles "everything under /articles" or "all the images". If you connect a bunch of these together you get your whole web server. Anyway, it turns out that it's much more fun if you simply pronounce ServerPartT as "Server Party":
So what's all this about monoids? Mathematically speaking, a monoid is a simple party game that some data objects can play when they get together. This is a mathematical definition in the sense that mathematicians are fun at parties.
The rules of the game are just that you have some way of appending things together; the tricky Haskell name for this is mappend, named after the famous French mathematician M. Append. Whenever you mappend two things together you get another thing of the same type that can also be mappended. There's also an empty element called mempty, or here called mzero(*).
So a monoid is just a way of saying how you connect things up. In terms of ServerPartTs:
- mzero corresponds to a 404: The empty part of your server is 404 Not Found; ie. if your server contained no application parts at all, it would just have to return 404 for any request. In general if a ServerPartT can't handle the current request (eg. the ServerPartT for images doesn't handle /articles then it'll act like mzero for that request).
- mzero `mappend` f = f: mappend is the way that you connect up two server parts. Basically you just try server parts one after another: when a request comes along, if the first ServerPartT can't handle it, ie. acts like mzero, then try the next ServerPartT (and hey let's call it f).
- if f is not mzero then f `mappend` g = f:
On the other hand, if the first server part
canhandle the request, ie. it does not return 404 and is not mzero, then use it and ignore all the other ServerPartTs (call them g). The whole server is acting just like f by itself!
The point is that because ServerPartT follows all the rules of the monoid party game, you can suddenly use all the functions available in Data.Monoid, like mconcat which takes a whole list of objects and works out what would happen if they were all mappended together. This allows you to simply make a list of ServerPartTs and use the first one that doesn't return 404: you don't even need to write a function for evaluating your whole server, you can just use the plain old boring mconcat from the base libraries!
The structure of monoids (stuff that can be appended) is pretty trivial, but very common. I highly recommend sigfpe's Haskell Monoids and their Uses to learn about some other more general uses.
As for Happstack: it's obviously a bit deeper than your average web framework. In this article I've only looked at the basic idea behind making a server; it has many more features for managing data, transactions and scaling. So what do you think? Is the monoidal mumbo-jumbo useful or does it just add a layer of confusion? Would servers really wear party hats to a ServerPartT?