In the tradition of “considered harmful” posts, this post’s title is intentionally misleading and designed to incite controversy — or at least grab your attention. Because of this, please take my exaggerations in this article for what they are :) In following tradition I will try to leave as many quotes and soundbytes as possible that can be easily taken terribly out of context and twisted.

Anyways, I don’t mean that this “IO Monad” is something to be avoid. In fact, there’s a lot I rather like about it. What I mean is that the phrase “IO Monad”…it’s got to go. It has its usages, but 99.9% of times it is used, it is used improperly, with much damaging effects. So let’s go ahead with stopping this nonsense once and for all, okay?

So I’ll say it here:

The phrase “IO monad” considered harmful. Please do not use it.

In most circumstances, an IO action of an IO type is the more helpful and more correct answer.

I’m going to say that this is probably the single most harmful and damaging thing in Haskell and the community, with regards to pedagogy, practice, public perception, and kittens. Not even kidding. It’s actually literally the worst and everyone in the world is worse off every time someone says it. Not only is this a problem in and of itself, but it is at the core root of 90% (+/- 80%) of Haskell’s problems.

Please, Not the “IO Monad”

Let’s say someone comes to you and asks you the question: “How does Haskell do things like print a string?”

The answer is: Definitely not with the IO monad.

This is literally one of the simplest questions a new person to Haskell could possibly ask. There are many incorrect answers you could give, but “the IO Monad” is one of the most incorrect answers possible.

For one, one of the most beautiful things about Haskell is that IO actions are all first-class normal data objects, like lists or integers or booleans.

The answer to this is that you use something of an IO action – something of an IO type.

You use an IO action (of the IO type)

> : t putStrLn "hello world" ghci putStrLn "hello world" :: IO () ()

There is nothing that has to do with monads at all in printing a string. The idea that putStrLn "hello world" is monadic is as absurd as saying that [1,2,3] is monadic.

Saying that the answer is the “IO monad” implies that the monad part is something important. It’s not.

IO in Haskell has nothing to do with monads.

Aside Okay, so the truth is a little more complicated than this. IO’s monadic interface is intimately intertwined with its history. It can be said that the reason why the model for IO that Haskell has was chosen is because of its monadic interface. The fact that this IO model admits a monadic interface was a major factor in its adoption as the IO model for Haskell. So, monads “have something to do” with the design decisions of IO in Haskell. But it is still true that IO doesn’t need to have a monadic interface in order to do IO. But that isn’t as nice of a one-liner/sound byte now, is it? Special thanks to Chris Allen and Kevin Hammond for this important clarification.

You could take away monads and even the entire monadic interface from Haskell and Haskell could still do IO with the same IO type.

The ability for Haskell to work with IO comes from the fact that we have a regular ol’ data type that represents IO actions, in the same way that Bool represents a boolean or Integer represents an integer.

Saying “the IO monad” is literally the most misleading thing you could possibly say. IO in Haskell has nothing to do with monads.

How did this idea become so prevalent and pervasive? I cannot say! But somehow, somewhere, this idea happened, and it is persistent now. Please do not add anything to this misconception and further propagate this dangerous myth.

Saying “IO monad” is very misleading and awful pedagogy because when someone new to Haskell reads that you print strings or do IO actions using “the IO monad”, the natural question is: “What is a monad?”

Not only is that question completely irrelevant to doing IO at all, it’s also a question that has historically lead to much confusion. I consider it one of the worst “sidequests” you could embark on in learning Haskell. Seeking an intuitive grasp of what a monad is is not only worthless for learning practical Haskell (at the start), but one that can lead to many false answers, confusing and contradictory answers, and just a lot of headache in general. Before I even ever heard about Haskell, I heard about the infamous “IO monad”. I read, “monads are a crazy hard-to-understand subject, but once you understand it, Haskell becomes amazing.” Haskell is Haskell and is useful before you ever introduce Monad into the picture…and a quote like that implies that understanding monads is important to understanding Haskell or IO.

It just simply isn’t. If you want to “understand Monads” (whatever that means), then go ahead; try. But please don’t think that it’ll help you even a single bit in understanding IO in Haskell.

Saying “IO Monad” implies that understanding monads is some prerequisite to understanding IO, or at the very least that IO in Haskell is inherently tied to monads. Both are untrue.

Another commonly mis-answered question is, “How does Haskell, a pure language, handle impure side-effects?”

Again, the answer is anything except “the IO Monad”. If I were to make a list of the most misleading, incorrect, dangerous, and disgusting possible answers, this would be on the top spot. The IO type itself is what enables this. Not the monadic interface.

Bringing in the idea of “monads” into the idea really only leads to confusion, because they literally contribute nothing to the subject. And yet, why do I see people answering, “Haskell handles IO and impurity with monads”? I’m sure you’ve heard at least one person saying this. But it’s 100% wrong. Monads actually have nothing to do with it, and I’m not even exaggerating here.

If anything it adds to the perceived learning barrier of Haskell. If something as simple as IO requires category theory to understand, then something must be way off. (Luckily, it doesn’t) This really only adds more to the perception of Haskell as an academic language that people learn only to be able to feel smarter. Haskell already has a huge PR problem as it is; we don’t need people going around doing this and making it even worse. Please, do not contribute to this.

Furthermore, imagine someone new to Haskell asked you, “Can I store a sequence of numbers?”

One good answer would be, “Yes, with a list!”, or the list type.

One bad answer would be, “Yes, with the List Monad!”

Now someone who wants to be able to do something simple like [1, 2, 3] will think that something like [1, 2, 3] in Haskell is inherently tied to monads in some way.

But having a list like [1,2,3] has nothing to do with monads. Calling every list “the list monad”, or calling every situation where a list would be useful a situation where “you want the List monad” is misleading, false, and just leads to more confusion.

I need to find all even numbers from one to one hundred.

Right: Use a list and filter even over a list from one to one hundred.

Wrong: Use the list monad and filter even over a list from one to one hundred.

Even more wrong but you couldn’t really get more wrong in the first place: Use the list monoid and filter even over a list from one to one hundred.

Why would you ever do that?

What good does it do?

What good has it ever done anyone?

Really, why?

Why do people say the IO monad?

Why did people start saying that in the first place?

Why doesn’t this world make any sense?

Please, please, stop saying “the IO monad”.

Some side notes