There's a lot of confusion around understanding monads, and I remember having trouble understanding them. Here's the two things that helped me the most: understanding kinds, and staring at the type signature for >>= for a long time. I'll attempt to explain both of these here:

Just as expressions have a type signature, a type expression has a kind signature. In its most basic form, a kind tells us how we can construct a type. We represent kinds by using asterisks * and kind functions ->. The asterisk is pronounced as "type". The easiest way to understand kinds is by looking at a bunch of examples of types and type constructors. Monomorphic types such as Int and Bool have kind * . Type constructors are handled differently. An example of a type constructor is [] (list), which has kind * -> * . So list is a type constructor that takes in a type (which we represent with an asterisk), and returns another type. Therefore [Int] has kind * , since we applied the type Int to the list type constructor [], resulting in the type [Int]. Types constructors can also in some situations be partially applied, just like value constructors. Kinds are right associative, so the kind * -> * -> * is the same as * -> ( * -> * ). I have a table of different kinds on my blog here: http://www.calebh.io/Type-Inference-by-Solving-Constraints/

Now that we understand kinds, we are now ready to understand monads. In Haskell, type classes are used to overload functions in a disciplined way. One such function is >>=, which is defined in the Monad type class. When we want to make a new Monad for a different type, we overload the >>= function. Since the >>= function is the most important function in a Monad definition, here is its signature:

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

How do we interpret this signature? Well we can see that the >>= function takes in two arguments, one of type "m a" and another of type "a -> m b". Remember the kinds from earlier? In this case, "m" is a type constructor of kind * -> * . So "m" could be the list type constructor, the Maybe type constructor, or really any other type constructor that has this kind. It can even be a type constructor that we define ourselves. So what can an instance of the >>= function do with the first parameter? Well it can do anything that it wants, as long as it follows some laws, which I'll talk about later. However notice that bind also takes in a second parameter of type "a -> m b", which is a function that takes in a value of type "a" and returns a value of type "m b". So the >>= function might end up calling this "callback function" and using its result. It could even call this function multiple times if it wanted to. The point is that >>= can do anything as long as it adheres to the type signature and follows the monad laws.

The monad laws are not as relevant when learning how to use monads, but I will cover them anyway. When you write your own overloaded instance of the Monad type class, you have to make sure that your overloaded functions follows these laws:

Left identity: return a >>= f ≡ f a

Right identity: m >>= return ≡ m

Associativity: (m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)

You can think of these laws as analogous to the laws for operations on numbers such as commutativity and associativity.