This is the deal: Haskell monads are often misunderstood to the detriment of Haskell projects across the 'net.

The reality is that they are extremely easy to understand when you describe them in plain language: They are wrapped functions that take a context and return some value plus a new context.

Here's a definition for a 'State' monad that implements mutable state:

newtype State s a = State { runState :: s -> (a, s) }

Or more simply:

newtype State s a = State (s -> (a, s))

Let's take a look at a basic computation using the State monad:

plus :: Int -> State Int Int
plus a = do
  s <- get
  put (a + s)
  return (a + s)

Let's rewrite that without the 'State' monad.

plus' :: Int -> Int -> (Int, Int)
plus' a s = (a + s, a + s)

Using monads can reduce the number of parameters in your functions and allow you to reason about them more freely. Monads also give you tools that enable you to bypass the use of a where clause in f below:

f x s = ...
    (a, s) = plus' x s


f x = plus x >>= \x' -> ...

If you're into how Haskell code could theoretically be optimized at a machine level, a monad could be evaluated down to a set of functions which could be compiled and their ASM concatenated. You could probably also rewrite them to avoid extra stack frames. This would mean that both plus and plus' would generate the same machine code.