What is a monad
Monad is a trait with the following operations:
Having such trait implementation for a type M makes it a monad instance.
Sometimes, pure is called return or point, whereas bind might instead be named flatMap (preferred in Scala) or >>= (Haskell's way). The method names are not so important, what's important is their signatures and what they do.
pure and bind implementations must obey some easily google-able mathematical laws omitted here to make things less boring.
M type parameter
Type parameter of higher kind M requires a monad instance to be parameterized by a type with a single type parameter, e.g. List, Future, Option, ({ type λ[A] = Either[Throwable, A] })#λ, or any type similar to:
pure operation
In a nutshell, pure gives a way to wrap a value of type A into type M (sometimes called monadic context). E.g.: List(a), Future { a }, Some(a), Right[Throwable, A](a). Put clearly: pure is A => M[A], and that's it.
bind operation
The essence of this operation is to allow flattening of M[M[A]] to M[A]. This might be not clear immediately, given the above Monad trait definition, but that's easy to understand: having a value ma: M[A] and a function f: A => M[B], to apply this function to ma, one needs a way to apply f to an a: A that's inside the context M, and the result will be of type M[M[B]]. So, bind allows to apply a function to monadic values and to flatten nested monadic contexts, while pure - to add new ones. For example, List(a).flatMap(a => List(a)), Future { a } flatMap { a => Future { a } }, Some(a).flatMap(a => Some(a)). These are artificial examples, but it's easy to imagine some nested conditional logic in the supplied f function.
Different perspective on Monad trait
It turns out, Monad trait might be formulated in a different way that is closer to the flattening intuition above:
Here, join (or flatten) does exactly that. Also, we've got a map operation which is needed to fill the 'gap' from loosing the full power of bind. Those two definitions are equivalent: bind can be implemented in terms of join and map:
or map and join in terms of bind and pure:
Different perspective on map and bind
There is also an alternative view on map and bind methods signatures. Let's call 'em lift and liftM accordingly:
Notice how similar they are. Both take a function, either ordinary A => B in case of lift or a monadic one A => M[B] (sometimes called Kleisli arrow) in case of liftM, and lift it to a function that works on monadic values. And these definitions are easily expressible in terms of original map/bind:
So, from this perspective, a monad can also be defined using pure and liftM or pure, join, and lift.
The essence of monads
From the dry definition above it might be not clear how monads can be useful, why they exist in the first place. So, to put it simply, monads give a way to chain computations (of type A => M[B]) while abstracting some details of how to exactly do that (extract values out of monadic context and flatten nested contexts) into the monad itself. For example, for Listss it performs flattening, for Options it stops on first None, for Futures - allows to make another asynchronous computation from within asynchronous computation, for some more esoteric state monad - to emulate mutable state in pure functional setting. This is what actually happens in Scala when using for comprehension syntax (though it doesn't force to implement any kind of trait, like the Monad above: just follow the method signatures, and all' be fine):
And it's just a syntax sugar for:
Unlike the Monad trait definition above, monadic operations here are written in object-oriented style, but that doesn't change their meaning.
Some monad instances
A monad's essence is in how chaining (bind operation) is implemented. So, here some monads instances to make it all clearer:
Notice how partial type application is used for Either which has two type parameters while monad requires just one. In general, for types having more than one type parameter, one needs to fix all the parameters but one to make an, in fact, a new type that could potentially be a monad instance.
Conclusion
Don't expect to understand the nature of monads just in one seat if you are new to them: you definitely need to play with various monads, see how they behave, implement some of them on your own. But the underlying idea is simple and is just a common programming practice: separate concerns and, as a consequence, prevent code duplication, by moving common stuff into a single easily maintainable and comprehensible place.