I've noticed the same thing - Haskellers are terrible at describing them. I'm not at all a Haskell expert, but I think I understand enough of Monads to explain them.
Yes they are as simple as people claim they are, and if you've done any functional programming you may already know them.
1.
Imagine a datastructure and a value. In this case we'll use "List" as the datastructure, and "Int" as the value.
So [3,4,5]. It's type is List<Int>.
2. Next we'll take "f" as a function that converts a single value to a list of values (ie a datastructure of our values). In this case the function takes a value and outputs a list of 3 copies of the value.
ex. f(8) = [8,8,8]
The type of f is: Int -> List<Int>
// Takes in an int, and returns a list of ints.
Also imagine a function "g" that does the same thing but makes 5 copies of the data.
ex. g(7) = [7,7,7,7,7]
It has the same type as f: Int -> List<Int>
3. How we apply the function to the data:
Frequently when we have lists and functions over their values we will call map over them.
_.map(f, [3,4,5]) = [[3,3,3],[4,4,4],[5,5,5]]
Notice that we don't get out a list of ints (type: List<Int>), instead we have a list of lists of Ints (type: List<List<Int>>).
We also often like to create/compose chains of these functions to create a pipeline to transform the data. So normally we would want to do something like:
r1 = _.map(f, [3,4,5])
r2 = _.map(g, r1)
But we can't. r1 is of the wrong type to pass into the second map. r1 is a List<List<Int>>, but the g is expecting a List<Int>. So how do we fix this.
How do we turn
[[3,3,3],[4,4,4],[5,5,5]] into a flattened list of ints? We append them.:
[3,3,3] ++ [4,4,4] ++ [5,5,5] // where ++ is list append in this language
the end result is [3,3,3,4,4,4,5,5,5]. Which is perfect. This is now something that we can pass into the _.map(g, ...) above.
We first 'mapped' transforming List<Int> -> List<List<Int>>. Then we "flattened" so that List<List<Int>> became just List<Int>. This allowed us to run map with g next.
This combination is bind.
Now the absurd part. If you've used something like C#'s linq there is a function that does this. It's called "SelectMany()". SelectMany is bind. It converts each element in a list to a new list, then flattens and appends the nested lists into a single list.
Bind is nothing more than SelectMany().
The only notable piece is that bind is abstract. There are different incarnations of bind for each datastructure. SelectMany is the bind for Lists. There is a different implementation of bind for "Maybe" type. Or other datastructures.
And a Monad is nothing more than a datastructure that supports SelectMany/bind. List is the one that you use all the time. The selectMany concept generalized to any datastructure is the concept of bind + a Monad.