The road to proficient Haskell

January 11, 2020

On the Haskell subreddit, /u/IronGremlin recently posted a really good checklist for becoming proficient at Haskell. If you’re struggling to go from zero to writing things like basic web servers or applications, give it a look!

However, the list is just that: a list of what concepts to learn. You might be wondering where or how to learn them; in some spots it’s a bit vague about what you should be doing. So here’s my recommendation about what resources and exercises to use for each step. May it help you on your path to proficiency.


  1. Learn to read function definition syntax, sans any extensions
  2. Learn to write and use basic ADTs to represent simple structures
  3. Learn to read a function type signature

Read chapters 1-4 and chapter 8 of Learn You a Haskell for this.

As a specific exercise, try implementing a binary search tree with some simple operations: search, insertion, and deletion. Don’t worry about balancing the tree.

One thing I’d add to the things you’ll want to know here is to get comfortable with both sum types and pattern matching; you’ll be using them a lot.

  1. Learn to write recursive functions instead of loops
  2. Learn how to use higher order functions on list to do most of what you can do in step #4

Chapters 5 and 6 of Learn You a Haskell.

For the addendum of why using higher order functions isn’t always the right choice, try implementing a function that takes in a list of numbers and returns the shortest prefix of the list that sums up to ≥ 1000. Once with normal recursion, once with folds.

  1. Learn do notation and do some stuff in IO to make actual programs

Ah, the pit of monads. You’ll want Chapters 8 and 12 of Learn You a Haskell. However, you probably won’t feel totally comfortable even after those.

There are a billion monad tutorials on the internet, but the ones I recommend are Dan Piponi’s You could have invented monads and my own monad tutorial.

  1. Learn Functor and Applicative

Chapters 11 and 12 of Learn You a Haskell.

This is another place where you might get confused for a while. Learn You a Haskell can get you started here, but I’m not sure it does a good job of explaining why these things exist and what they’re useful for.

Unfortunately I don’t know of any good resources that explain that simply, so you’ll need to learn by doing. One exercise you can do here is to learn how to use optparse-applicative. Stop here and implement a simple CLI application that you’re interested in. Ponder the type signature for liftA2, and compare it to what a Functor gives you.

  1. Understand that steps 6 and 7 are all anyone actually means when they talk about learning to use monads
  2. Understand, again, that all a monad is is something that implements (>>=) and return, and follows the laws

This part is on you. Spend some time reflecting on what you’ve learned so far.

  1. Use a bunch of stuff that has a monad instance in IO and get irritated about it.

Specifically, try doing error handling by pattern-matching Maybes inside some IO block. For instance, you could write something that parses JSON (using aeson) and does stuff with it.

Even more concretely, write a bunch of functions with types like a -> Maybe b, a -> IO (Maybe b), a -> IO b etc. and try building a working executable out of them.

  1. Learn about typeclasses

Chapters 3 and 8 of Learn You a Haskell.

In addition to the typeclasses mentioned in the list, you should also study the Eq and Ord typeclasses. Try manually implementing instances of Eq and Ord for:

The list also mentions learning about minimal. For typeclasses where the class has a lot of methods, but some of them can be derived from others, the MINIMAL compiler directive tells users which methods they actually need to define for instances of said typeclass. For instance, Eq lets you define either (==) or (/=); the other one can be derived by negating the other.

  1. Write your own monad instance for a type that combines the effects of State and Either

Think back to step 10. The point here is to alleviate the pain you felt then by creating a type that has both functions to retrieve/set the current state and one to short circuit, without needing to write the boilerplate you needed then.

Remember, all you need to do is define two functions for your type, (>>=) and return.

  1. Learn about newtypes

Chapter 11 of Learn You a Haskell.

  1. Learn about the ‘safe constructor’ paradigm

Haskell Wiki, “Smart constructors”. Ignore the section on compile-time checking; it’s not relevant at this point and isn’t what most Haskellers would think of when they hear “safe constructors.”

  1. Understand what a ‘partial function’ is

Not a large enough concept to require dedicated reading; Google is your friend here.

Once you understand what a partial function is and why you don’t want to use them, take a look at the safe package for a solution.

  1. Learn about module imports/exports

Chapter 7 of Learn You a Haskell.

Once you’re up and running with a build system in step 17, come back to this and play with it some more. Create some empty modules and a file hierarchy and make sure you’ve got things down.

  1. Learn either stack or cabal

Build tools for Haskell that help you manage your project and project dependencies.

I personally recommend Stack when starting out, but either one is fine. They both have guides on getting started, so learn one and stick with it.

  1. Learn how to use monad transformers so that you never have to do step #12 again

A Gentle Introduction to Monad Transformers and the Haskell Wiki’s entry on monad transformers are both pretty good here. Gentle Introduction in particular does a good job of motivating why monad transformers exist, although if you’ve already done step 12 you should already start to see why.

As an exercise, try implementing StateT and EitherT yourself.

  1. Learn to use lens to access and manipulate record types inside a collection

I think the best resource on the very very basics of lenses is, oddly enough, the tutorial on an F# lens library. The syntax is slightly different, but it does a good job of motivating the abstraction as well as showing that lenses are not magic.1 You can implement them yourself by (surprise surprise) composing functions together.

Past the basics it gets a little murkier. The canonical text is Chris Penner’s Optics by Example, but right now that’s massive overkill. Try working through the exercises in my lens exercises post; up through the section on Folds and Traversals should be plenty.

  1. Learn when and why to use bytestring, string, and text

Alexis King’s Opinionated guide to Haskell in 2018.

Once you need to start using and manipulating strings in your own programs, I recommend my own string-interpolate package.

  1. Write a parser using Parsec, Megaparsec, or Attoparsec

megaparsec is your best bet here, as it’s optimized for better error messages, compared to attoparsec. parsec shouldn’t be used for real code, as megaparsec is better in pretty much every dimension.

If you’re not sure on a project, why not try implementing your own JSON or XML parser?

  1. Write a simple web server, CLI, or GUI app using the skills above.

To save you some time, here are some libraries you’re likely to need:

There’s no cookie-cutter solution to any of these, and you’ll have to learn to plug together bits and bobs yourself.


Good luck on your Haskell journey! Remember as you go along that it’s normal to get stuck on some steps; wrapping your head around the functor-applicative-monad trio and monad transformers seems to be a big hump for people. Ask questions if you feel like you’re running in place. Put things down and give it time to sink in. Presumably it’s not mission critical that you write production Haskell next week. I personally put down Haskell for a long time before coming back and having it click, and I know many others in the community had a similar trajectory. So take it at your own pace, and once again good luck!

Found this useful? Still have questions? Talk to me!


You may also like


Footnotes

↥1 For basic things at least. Once you start getting into profunctor encodings, things get a little hairier.


Before you close that tab...