To start off, we have to understand that a Monad is not state, impure, imperative sequencing and so on. It can be used to model these, but it isn’t defined as those things.

We can think of it as a pattern we observe.

In the context of Haskell, when a certain type we use obeys monadic laws, we can call it a monad.

There are 3 laws a monad has to obey:

Lawdefinition (>>=)definition (>=>)definition join / j
left identityreturn a >>= f = f areturn >=> g == gjoin . return == id
right identitym >>= return = mf >=> return == fjoin . fmap pure == id
associativity(m >>= f) >>= g = m >>= (\x -> fx >>= g)f >=> (g >=> h)j . fmap j = j . j

A way to gain intuition if something is a monad is to gain intuition for these laws.

Recognize if a type follows these laws.

Let’s see some of the things that Monads allow us to do:

It allows us to wrap some value, a within a monadic context:

return :: a -> m a

It allows us to compose functions which return values wrapped in monadic contexts:

(>=>) :: (a -> m b) -> (b -> m c) -> (a -> m c)

It allows us to collapse contexts.

join :: m (m a) -> m a

It allows us to apply a function a -> m b to a value, a within a context m and combine the contexts (one from m a one from m b).

(>>=) :: m a -> (a -> m b) -> m b

So where is this pattern useful?

Some examples:

References: Bartosz milewski - Monads Haskell wiki - Monad laws Stephen Diehl - Eightfold path to monad satori