September 4, 2011
(This post is also available in Serbo-Croatian. Translation by Jovana Milutinovich.)
I’m learning Haskell. Maybe you should too. Here’s why:
Every programmer has something to say on what other programmers should know in order to be standouts in their field. Back in 2004, for instance, when Python was more obscure than it is now, Paul Graham wrote an essay about something he called the Python paradox. In that essay, Graham summarized the paradox as follows:
… if a company chooses to write its software in a comparatively esoteric language, they’ll be able to hire better programmers, because they’ll attract only those who cared enough to learn it … [Thus] the language to learn, if you want to get a good job, is a language that people don’t learn merely to get a job.
I won’t go into the details of Graham’s reasoning behind the paradox (you can read the essay for that), but I think it has legs. The best programmers are those who love their craft — the ones who love it so much they’ll learn unpopular languages just for the fun of it. Simple enough. As an addendum to Graham’s advice, however, I’d add the following: The best programmers should also have a high- or expert-level competence in at least one language from each of the three following groups: the large-scale object-oriented languages (Java, C++, C#, ActionScript, etc.), the dynamically-typed “scripting” languages (Ruby, Python, Perl, etc.), and the functional languages (Scheme, OCaml, Haskell, Clojure, F# and friends).
Thus, if you’re going to learn a new language, pick one from the group that is least represented in your repertoire. If you’re like me, this means the language to learn is a functional language. An esoteric functional language. Yes, it’s time to leave your comfort zone.
At the beginning of 2011, I decided to make Haskell my programming language of the year. This was not without significant deliberation. Learning a new language requires a substantial investment of time and mental energy. And Haskell is certainly not the most popular functional language. (Clojure and Scala — both of which run on the JVM — have seen a rapid surge of popularity as of late.) But I don’t learn new things simply to retain employment. I learn them because they’re interesting. Here’s why I found Haskell to be the most interesting of them all:
Syntax matters, and I prefer to write in a language that looks and feels elegant. Elegance was the allure of Ruby when a first started learning it five years ago. Elegance is the allure of Haskell for me now. Certainly there are different types of elegance. Lisp and its kin (Scheme, Clojure) are elegant in their simplicity (everything’s a list!), but not in brevity. I’m happy to learn more syntax if it means I type less (and don’t have to manage parentheses). And I like languages that allow syntactic variations for accomplishing the same task. As Larry Wall, the creator of Perl, notes, syntactic variety has an anthropological analogue in human languages. Perhaps that’s why, at least to me, the weird syntactic nooks and crannies, and “polyexpressiveness” of languages like Ruby and Haskell just feel right. That, and it’s just more fun.
The canonical example used to illustrate Haskell’s elegance is quicksort. Here it is (original source):
qsort  =  qsort (x:xs) = qsort less ++ [x] ++ qsort more where less = filter (<x) xs more = filter (>=x) xs
Four lines! And it reads just like how you would describe the algorithm: A list is sorted if all the elements smaller than the front of the list are moved to the front list (and sorted), and all the elements greater than the front are moved to the end (and sorted).
There are few areas of life where laziness can be considered a virtue. Computation is one of them. Haskell is lazy in the sense that it only evaluates code when it’s absolutely necessary — allowing you to avoid wasting precious CPU cycles. And make use of some fairly nifty code tricks, like using infinitely long lists. Consider the following:
take 10 $ filter even [0..]
This will result in a list consisting of the first 10 even integers from 0 to infinity. Because Haskell is lazy, it will never try to create an infinite list (impossible anyway), but only create the elements of the list it actually needs.
Consider also this example based on quicksort from above:
minimum list = head $ qsort list
This defines a function that gets the smallest element of a quicksorted list. In a non-lazy language, the entire list would be sorted first, then the head (the first element) of that sorted list would be returned. That’s a lot of wasted work. In Haskell, the list is only sorted enough to give the correct answer, and that means you only need to sort the elements that are lesser in value than the first element of the original list.
Like all functional languages, Haskell has no side-effects. Side-effect free programming is rapidly becoming a necessity as we move to writing code that runs well on multiple cores. It also means fewer bugs. Purity is where it’s at in the 21st century. And unlike some other functional languages, Haskell pursues purity as strictly as possible. “Pure” code and “impure” code (like code used for IO) remain neatly and permanently separated (through the use of monads) so that you can continue to reason about your pure code without it being “tainted” by side-effects.
Type inference permits all the benefits of strong typing without all the typing (no pun intended). This means that you get type safety, without having to explicitly declare the types of everything (unless you want to). The Haskell compiler is smart enough to infer what the types of things should be, and you can continue to code on your merry way knowing that the compiler has got your back.
Coming from languages like ActionScript and Java, this is perhaps one of my most favorite features of Haskell. The amount of key banging it saves is enormous, and the code looks as simple and elegant as any dynamically typed language.
By far the best resource for getting started with Haskell is the freely available book, Learn You a Haskell for Great Good. It’s friendly, approachable, and easy to follow. Those coming from the Ruby community will find it reminiscent of the playful style of _why’s Poignant Guide to Ruby. I can’t recommend it enough.
Those looking for something more traditional may prefer the (also freely available) Real World Haskell. It’s another great book from O’Reilly, but not nearly as fun.
Learning Haskell may not get you a job programming in Haskell, but as Paul Graham postulates, it may still get you a job. Personally, I find that irrelevant. Learning the language has proven to be fun and rewarding and I plan to continue my Haskell adventures into 2012.