I find that monads are easier to explain in the context of programming that in category theory.

First, start with a functor. In terms of programming, a functor is container with an associated function (often called map or fmap -- I'll call it map since fmap simply stands for "functor map"). map takes the contents out of the container, applies a function (which you pass to map) and puts the results back into the container again.

It's important to understand that the function may change the type, so while you have the same kind of container, the type of data inside may change. For example, imagine your functor (container) is an array of integers and your function takes an integer and returns a char. The result of running map on your functor is an array of chars. This may seem trivial, but it is important later.

One other thing to realise is that anything that can "hold on" to a value and for which you can implement map is a functor. So arrays, lists, tuples, hashes/dictionaries/objects etc are all examples of functors. Even a function that has a closure over a parameter can be a functor -- as long as you have a way of implementing map (left as an exercise for the reader).

Monoids are usually not explicitly identified in most programming languages. You can make functors that can contain anything (i.e. the set that represents the values it can contain is allowed to be empty). So basically, you can contain a functor that contains only nothing. A monoid is a functor in which the set that represents the values it can contain can not be empty. In other words, it must be able to contain a value. Also it must have an "identity" value for a given operation. The identity value is one for which when you perform the operation, you get the same value back. For addition and integers the identity value is 0 (n + 0 = n). For multiplication and integers, the identity value is 1 (n * 1 = n). For concatenation and strings, the identity value is "" (s.concat("") = s). Most functors (remember, just a fancy word for container in the context or programming) are monoids for a given operation.

An endofunctor is just a functor (container that you can implement map on) for which the type you start with is exactly the same as the type you end up with. For example, if you have an array of integers, apply a function to the contents with map, and you end up with an array of integers again, then you have an endofunctor ("endo" just means that it's the same on both ends). If you ended up with an array of strings, then it's not an endofunctor because an array of integers is different than an array of strings, even though they are both arrays.

A monad is just a monoid (container that can hold at least 1 element and for which there is an identity element for the function you will be applying) in the category of endofunctors (you'll get exactly the same type after you apply the function).

Usually instead of map (which automatically puts the transformed values into the container) you use a function called bind with monads. bind works pretty much the same as map, except that the function you pass to bind needs to put the transformed value into the container. You would think that this is a PITA, but it's very necessary in many situations (easiest way to see this that I know of is to try to implement an "either monad" with only map -- you'll see right away that it's not possible).

And that's it, really. I find it really interesting to understand how category theory works, but it is not at all necessary for understanding how to use functors and monads while programming.

Edit: I forgot the most important part! Why do a want a monad? Since it always returns the same type from bind as what you started with, it means you can chain functions. I've found that it's also really helpful in non-type checking languages for reasoning about the type of things. If you are using bind on a monad, you know that chaining will work every time -- you never need to check for null, etc.