Monads in Haskell

Monads…
Yeah, I know — it sounds weird the first time you hear it. When I first started learning Haskell about three years ago, the word itself felt mysterious, almost intimidating. Even in my free YouTube course, I don’t think I ever explained it in a way that truly clicked for everyone.

So this time, I wanted to fix that.

In this video and article, I’ll walk you through what Monads actually are — but not by dropping the term on you out of nowhere. We’ll start from the ground up: Functors, then Applicatives, and only then arrive at Monads.
Each step builds naturally on the one before it — and once you see the pattern, it stops being abstract and starts to make sense.

Step 1 — Functors: applying a function inside something

A Functor is any type that can be “mapped over.”

You already know this idea from other languages:
In Python, you’d do [x * 2 for x in numbers].
In Haskell, it’s fmap (*2) (Just 10) → which gives Just 20.

The wrapper (Maybe) stays the same — you just apply a function inside it.
That’s all a Functor is: a context you can apply a function to, without unwrapping it.

Step 2 — Applicatives: applying a wrapped function to a wrapped value

Applicatives go one step further.
Imagine having both the function and the value wrapped:
Just (2) <> Just 10 → gives Just 20.

It’s basically saying:

“I’ve got a boxed function and a boxed value. Apply one to the other.”

And when something’s missing (Nothing), the whole thing fails gracefully.
Applicative also gives us pure, which just lifts a plain value into a context, like:
pure 5 → Just 5.

Step 3 — Monads: chaining things that return wrapped results

Now comes the big one — Monads.
They let you chain functions that each return their own wrapped result.

For example:

safeDivide :: Float -> Float -> Maybe Float
safeDivide _ 0 = Nothing
safeDivide x y = Just (x / y)

Using the “bind” operator (>>=), we can write:

Just 100 >>= (x -> safeDivide x 2) >>= (y -> safeDivide y 5)
— Just 10.0

If any step returns Nothing, the whole chain stops.
So Monads are basically a clean, composable way to handle context — whether that’s “might fail,” “has side effects,” or “depends on previous results.”

And if you prefer cleaner syntax, do notation does the same thing with less noise.

Wrapping up

Functor → apply a function inside a context

Applicative → apply a wrapped function to a wrapped value

Monad → chain functions that return wrapped values

That’s it — the scary word hides a very simple pattern.

You’ll see it everywhere in Haskell: Maybe, IO, Either, List — all of them are Monads. Once you understand one, you’ve got them all.

If you want to see this concept click into place, check out the full video — I walk through everything live in GHCi with examples and visuals.

Similar Posts