My experience of rewriting this website's engine in Haskell was surprising and disappointing at the same time. What I initially expected was the heroic quest filled with fierce battles against the creepy Monads and ending with the Hero (hehe, me) drinking from the Holy Grail of Catamorphic Wisdom. How it actually turned out is described in this essay.
At the moment when I decided to create this "antiblogging" website, under my belt I had around two years of experience programming websites in Python, PHP and JavaScript, and being paid for that. Naturally, I wanted to try something different. That is why I picked PL/pgSQL (that's PostgreSQL's flavour of procedural SQL which I never used before but wanted to try out sometime anyway) for parts of the business logic and Java (which I programmed before for few years) for the web layer.
Then I put together the website1. And then I saw every thing that I had made, and, behold, it was very good.
Except that it wasn't.
Well, PL/pgSQL part was okay. Actually, I have to admit, I like this language. It is highly specialized in moving values across the database and isn't suitable for anything else, and still, despite of it's limitness and COBOL-ish syntax, it is very good for describing exactly what I want to happen with the data.
Words "exactly what I want" are important here since with Java code, it just didn't happen. Because those thirty-some classes I've produced could perhaps match the definition of "what I can live with" but were nothing near "exactly what I wanted". So I tried to refactor them. "1000 lines added / 700 lines removed". Better, but still crap, try again. "600 lines added / 800 lines removed". Even better, but still bloated, and spending evening after evening after evening doing this feels boring. Especially when compared to PL/pgSQL part which remained not just stable but intact because, well, it already did exactly what I wanted.
I believe, that's a generic problem with Java. Java is bland and doesn't have powerful syntactic sugar and semantic chilly pepper to express simple things in a way other than being very verbose, and then comes a temptation to introduce some utility patterns to help to describe those simple things in a concise way, and then your "utility" code is twice as big as the original one, and you want to refactor it too, and that's a trap! Unless you're not as maniacally obsessed about the code's clarity as I am. Or unless you (or me or we together) are in a work environment where there are more interesting things to do than obsessively polishing a piece of code. But obviously neither of this applies to my personal hobby projects.
So, at some point I thought about rewriting it in something else, and I decided to give Haskell a first shot thinking that even if I don't succeed, at least I will learn some secret knowledge about all that fancy-shmancy monadic functional programming.
Next comes the list of things that I have actually learned from this exercise. Also, just to let you know, webapp that served you this page is written in Haskell, and I intend to wipe all Java sources from my git repo as soon as I finish writing this essay.
1. Perhaps the most surprising lesson is: while the popular opinion says that the main reason to pick Haskell is "to have fun hacking," in fact it's not so fun to hack in Haskell because there's not such much hacking to do at the first place. For instance, you don't need to spend lots of effort tracing and fixing obscure bugs, so if your definition of "hacking" includes heroic bugfixing, you'd be better off with JavaScript or Perl. You also don't need to do so much refactoring, so if you want to have fun doing it, you'd better pick Java. And if by "hacking" you mean typing in stockpiles of code, hardly anything beats C for that purpose.
But if you don't really like programming that much any more and just want a concise program that just works without putting too much effort into "having fun hacking it together," then you definitely should consider Haskell or a similar FP language.
2. However, despite the claims from aficionados that Haskell is a silver bullet that will magically solve all your problems and fix all your bugs, that's also not true. Haskell is more like a depleted uranium bullet; it timely detects most of my bugs, though some occasionally slip in.
3. But, probably, the most important lesson for me was that Haskell port didn't turn out to be an exact 1-to-1 clone of Java version's functionality. One such difference was usage of intra-process caches. In Java with DI container backing, it's harmfully easy to spawn a bunch of "service" classes that hold some chunks of data inside. In Haskell it's also possible, but must be done in a more explicit manner and thus feels somewhat messy. So, I wrote a cacheless version, then tested the performance, saw that it painlessly holds 100 rps without any tuning2 which is more than enough for a personal homepage. And so I purged all caching-related logic for good.
Was it possible to make these improvements to Java code? Yes, definitely. Was it possible to consider these improvements to Java code? Well, this is a very, very, very good question.
4. "Lack of ecosystem" is what usually shows up in every "Top 5 reasons I'm not going to use Haskell" list. But, at least for web development, it's not true nowadays. I guess that "nowadays" is the important word in the previous sentence as this website is built on top of blaze-html, Scotty and postgresql-simple, and all of those projects had begun around 2010-2012. So, probably, building a website in Haskell in 2008 was a different story, but it was same for $your_favourite_language before invention of $your_favourite_framework, and who cares now?
Today, Haskell has complete stack of whatever you might need to write a web backend, so "lack of ecosystem" is not a valid excuse anymore.
5. Not so much surprising to me, but maybe it is for some of this text's readers, Haskell is not that hard to program in. For the record, I don't have dual PhDs in computational semiotics and in abstract algebra, I'm just a humble enterprise/web developer who never used Haskell to write anything bigger than a Project Euler type of programs. Still, I can tell you that once you (a) learn to appreciate the mostly-stateless code with strictly localized mutable data3, (b) learn to appreciate the compile-time errors4and (c) wrap your head around monads5 then all that's left to do is to memorize syntax and libraries, and I assume you've done it multiple times before.
6. In the advertising materials there's much of emphasis regarding Haskell being "pure" from side effects and from that you might get an impression that no True Scotsman will (or even is able to!) write code with side effects in Haskell6. That's not true, it's totally possible to write impure code in Haskell, but there are some tricky details: in a conventional programming language having side effects is a kind of opt-out7and there are typically no special notation for it8. In Haskell, they're opt-in and you must use IO monad to designate it appropriately.
7. Strong typing is not just about autodetecting bugs you have in your JavaScript-ish code. It's more than that.
and, finally,
8. I bought myself a textbook on category theory. Just because Haskell itself is not especially mind-bending.
1 Just in case if you enjoy reading the lists of Java components used in this or that application, I've got one for you. Jetty, Velocity, C3P0, PicoContainer, Ant, Ivy, JUnit, IDEA.
2 And no, my site is not simple. It is lightweight and well thought-out.
3 That naturally comes from experience fixing bugs caused by shreds of mutable state being concealed in the random places of an application. Think of incorrectly invalidated caches for one example.
4 That naturally comes from experience fixing run-time bugs. In extreme haste, of course, 'cause they're already in production and users are unhappy.
5 Which don't directly correspond to the concepts found in conventional programming languages. However, once you shake off all that abstract algebra notions that you have seen in tutorials written by abstract algebraists and barely understood anyway, and realize that monad isn't much more than simply a generalization over an idea of a transactional container, then it gets smooth.
6 From that people often infer that since most kinds of programs can't be written in totally side effect-free manner, Haskell is likely to be not useful for their kinds of problems and avoid it altogether.
7 I.e. you're not forbidden from writing functions that only depend on input arguments and constants
8 I struggle to remember anything except const modifier in C++