You are already smart enough to write Haskell

Posted on October 5, 2019

It has still often been difficult to find answers to my questions. I think this is largely due to the fact that when discussing things with the average Haskell programmer, I feel like I have a fourth-grade education.

Much of the material on Haskell online seems to have been written by and for people with four more brains than me.

Whether you’re coming to Haskell from another language, or if you’re interested in writing programs that, y’know, actually do things, participating in the Haskell community can feel like you’re a second class citizen. Between the lack of solid documentation for many popular libraries, to the deluge of posts and articles about the hottest new effect programming sudofunctor, it seems as though you need 2 PhDs in programming language theory just to write Hello World. Picking up any other language seems like a straightforward endeavor; read a few tutorials, try to write a project that interests you, and you’re off. Why is Haskell so much more intimidating?

If you’ve already learned another language, you can learn Haskell. And even if you haven’t, learning Haskell is no harder than learning any other programming language.1

Why do all these advanced features seem so important when you’re learning Haskell? Because they’re all that anyone ever seems to talk about. No one talks about the boring, meat-and-potatoes parts of the language, because to anyone that has written Haskell for years and years, those parts come as naturally as breathing. But as a result, the perception of what tools, libraries, and concepts are important ends up distorted by novelty and excessive cleverness. If you strip this away, you’ll find that a lot of things that people talk about end up being unnecessary for writing practical programs. In particular, here are some things that you emphatically do not need to understand in order to write real Haskell programs:

  • category theory
  • lambda calculus
  • lazy evaluation2
  • lenses
  • monad transformers
  • effect algebras
  • recursion schemes
  • type programming
  • Template Haskell
  • proof languages like Coq and Agda
  • language extensions other than -XOverloadedStrings

Some of the abstract math stuff is utterly fascinating, but generally you don’t actually need to understand any of it to get work done.

From time to time, it will feel frustrating because you will know how to solve the problem in [some other language] but not in Haskell.

What do you need to write real Haskell? The core of the language is extremely simple. If you understand how to write and use

  • pure functions and values
  • pattern matching
  • sum and product types
  • how to glue together IO to make side effects

then you already have everything you need to write useful programs that solve real-world problems. With just these few concepts, you have everything you need to build anything you could build in Java, or Python, or Ruby!

There are plenty of valuable Haskell tools that don’t go beyond anything more complicated than IO and -XOverloadedStrings. Hakyll powers the site you’re reading right now, and it doesn’t use any complicated language extension-based machinery or monad stacks. Aeson powers JSON handling for the vast majority of Haskell code, and it doesn’t do anything fancy. time powers tons of datetime handling, mysql-simple provides database access… you get the idea. None of these packages rely on advanced concepts to implement their core functionality.


Does not having to learn these concepts right off the bat mean that there’s no point ever learning them? That we should all just abandon our effect algebras and category theory-based abstractions? No, of course not. If you’re choosing to learn Haskell, you’re probably naturally curious. Someone suggesting that you not bother understanding how things really work may as well suggest that you sell your mother to the mafia. But don’t force your forehead to get well-acquainted with brick walls made of type errors. Put aside the things with high learning curves for another day, and get something that works first.

Pace yourself.

Eventually you’ll be able to scale the mountain of abstractions that Haskell has to offer. You’ll give up a little bit of type-safety here, some static guarantees there. Remember that even with just the four core concepts we outlined above, you’re still getting more confidence from your compiler than any other language out there.3 And the great thing about Haskell is that you can incrementally upgrade to more advanced tools and frameworks, even within the same project. The strictness of the compiler grades your “test”; you’ll know once you’ve gotten it right. You can add in the ability for, say, restricting only certain parts of your codebase to be able to access the DB, allowing only some other parts to make HTTP requests, and so on, using freer-simple or transformers. You can try out a new way of structuring your tree transformations using recursion-schemes. And if you’re happy with your program, you can leave it working as is. There’s an endless amount of things to learn, but there’s nothing wrong with taking it at your own speed.

So the next time you find yourself banging your head against a screen’s worth of language extensions, take a step back from the heavyweight solution and see if you can solve things using something simpler, or something you already understand. Do you need the static guarantees of Servant, or can you get away with using Scotty? Do you need type-safe queries using Beam or Squeal, or can you get away with using postgresql-simple?4 Do you need to add permissions to your code using monad transformers, or is just IO enough? And on a simpler level, do you need to express some logic using a fold or a map, or can you get away with just writing out a recursive function yourself? You’ll probably find that the problem wasn’t as hard as you made it out to be.

Is there something in your codebase that you feel like you’re overthinking? Got a comment? Talk to me!


You might also like


Footnotes

↥1 In fact, it might even be better if you approach learning Haskell without any programming experience; it means that you won’t have to unlearn any concepts from previous languages.

↥2 You can write programs assuming that they evaluate values strictly and probably not run into any major problems. It might even be a good idea to enable the -XStrict GHC extension when starting out, just to make performance simpler to understand.

The big exception to this is if you plan on doing multicore parallelism, in which case you will have to care about laziness.

↥3 Unless you’re coming from an ML, Scala, or Rust.

↥4 Or equivalent simple library for your RDBMS of choice.


Before you close that tab...