
imo, the most import ingredient to understand monads, is to understand lazy evaluation. In Haskell, everything is about values. If you have a function f :: a -> b, then f x stands for a value of type b (nothing is evaluated yet). Now, if you have another function g :: a -> M b, then g x stands for a value of type M b, that is, a value of type b requiring something more (encoded by the monad M). Depending on which Monad you used, you need to do something the the value M b to get to the actual value b. In the case of the State monad, you have to run it with an initial state. In the case of IO, you can't do anything and so you have to give the value to the runtime-system (via the main-function). In the case of the List monad (which represents non-determinism), you can choose any element of the resulting list, or, more commonly, use every possible result (i.e. the whole list).
One thing is missing here: The interesting aspect of a monad is, that it always allows you to "compose". Via the bind function (>>=) :: m b -> (b -> m c) -> m c, you can take a value of M b and derive from it a new value of M c by using the previously encapsulated value b. -- Thomas Danecker