The Haskell Conundrum

Over the past few months, I've been toying with Elm. While I feel like it gets a lot of stuff right, one thing that really blew my mind was the effect that a good type system had on the way I write software; for the first time, I felt types were not only helping me, but also guiding the development and making the code more readable, understandable and safe from runtime errors.

I suddenly found myself wanting the same benefits on the backend, but Elixir - my favorite language in that battlefield - isn't really suited for that. And so I decided to learn Haskell. Again. For the third time. My previous attempts didn't really go anywhere, but this time I was determined to see it through. I got a highly recommended book, Haskell From First Principles and dug into it.

Haskell is a beautiful language, and the book does indeed do a great job at exploring its ins and outs, what makes it an unique language and so on. However, after reading through more than 10 chapters and 250 pages, I realized I hadn't really built anything. Sure, I had a much better understanding of how Haskell works and I even wrote some functions to manipulate data in different ways, but nothing I could really claim as useful or that I could even run as an application. Immediately, the ghosts of co-workers past that dismissed Haskell as an academic experiment with no commercial value started mocking me.

But why is it that Haskell has such a bad rep?

After some thinking, it dawned on me: you need a deep understanding of how Haskell works to build anything with it. OK, maybe not a deep understanding, but as Aragorn would put it, one does not simply write a Haskell application. Why? Well, take a look at this small command line application that prints a greeting based on the first argument passed to it (excuse the crappy Haskell, I'm still a beginner):

import System.Environment

main :: IO ()
main = do
  (name:_) <- getArgs
  putStrLn $ "Hello, " ++ name ++ "!"

If you started learning Haskell but didn't really get into it, you're probably scratching your head now. IO ()? do? <-? What are those?

Well, Haskell is a pure functional programming language, which basically means side effects are illegal. However, any useful application will need to perform side effects - get user input, print to the screen, etc. Haskell solves that in an elegant way: the IO monad. Working with values inside monads can be verbose, so the do syntax was introduced to make things shorter and more readable. Those are often seen as "advanced" concepts in Haskell, and therefore don't appear in learning materials until much later. In other languages, like Elixir, you get a command line app running after the first tutorial. In Haskell, you need to understand a bunch of fundamental (and reasonably complex) things before you get to that point.

And there, my friend, lies The Haskell Conundrum: the very thing that makes this language beautiful, its purity, is what makes it so disconnected from reality from the perspective of someone learning it. By the time you understand main, you'll probably know enough to write significantly complicated applications, but until then you're pretty much playing around in the REPL writing your own implementation of Fibonacci.


PS: I am really enjoying learning Haskell. This post is not about me bashing the language or the book in question - I'm just pointing out the complications of writing real-life code with it from a "newbie learning" perspective.