"A monad" isn't a thing, but we can ask what it takes for something to "have monad-nature" or "be a monad". For this to occur our something must be three things, a triple
(T, mu, eta)
The names are all meaningless so for the moment they just get short letters.
T must be what's known as a Functor. For PLs really, though, it's even more specific. It's an "endofunctor on the type category of your language". What this means is simple
* For any (static) type `a` in your language, `T a` is also a static type.
* For any function `f` from type `a` to type `b`, `T f` is a function from type `T a` to `T b`.
If your language doesn't have static types then you can approximate this by pretending that it does. Also note that `T f` is not usually the syntax used, but it'll do for now.
Now to make a monad we take any choice of Functor `T` and give it two operations. `eta` takes values in type `a` to values in type `T a` while `mu` takes values in type `T (T a)` to values in type `T a`. In other words they give you a "layer manipulation toolkit".
They must follow laws as well, but these laws are all "common sense laws" which allow you to think of values in the following types: `a`, `T a`, `T (T a)`, `T (T (T a))`, `T (T (T (T a)))`, ... as all being the same as values with just one layer: `T a`. This is the "flatten" idea.
And there you have it! Anything at all which can be regarded as equivalent to one of these triples following this design and laws is a monad!
---
So the real question is why should someone care? The answer is simple.
Lots of things have monad-nature in a typed language. By recognizing their common nature we can (a) see them in a new light full of perhaps previously unknown similarities, (b) share terminology lightening the burden of how to use them, (c) write generic operations which work over any monad and expect them to work with each specific one in a similar way, (d) introduce new syntactic sugar which is built entirely from (mu, eta) and expect it to work similarly for every thing with monadic-nature, (e) begin to form theories and impressions of "what it means to be a monad".
The reasons (a-d) show up all the time once you recognize this pattern since monads are really common.
Reason (e) is what everyone wants to hear about but it's hard to talk about without being super arm-wavey. But I'll try.
In order to provide the operation `mu :: T (T a) -> T a` the type `T a` must be able to "internalize itself" without losing too much information. In order to follow the laws, one bit of important information is an idea of sequence or nesting—but one unique to each particular monadic triple.
In this way monads are a very, very, very general way of talking about sequencing or nesting.
What makes thins interesting is that you can see imperative languages as being about sequencing or nesting as well. If you have a listing of statements { X ; Y ; Z } then you can see { Y ; Z } as being nested in the execution context that X created and { Z } being nested in the execution context that { X ; Y } created.
This would maybe make you think that imperative languages have monad nature and indeed they do. This leads to an interesting study of questions like "For some given imperative language, what is a pure-functional representation of the monad representing it?" which sometimes has interesting answers.
What's even more interesting is that one example of reason (d) above is to introduce a syntax sugar which makes any monad look a bit like an imperative language. This leads to an interesting study of questions like "What does the imperative language for some monad X feel like?"
So if you really like imperative languages and recognize that there's a larger design space here that most have any familiarity with then monads are a good thing to keep an eye out for.
"A monad" isn't a thing, but we can ask what it takes for something to "have monad-nature" or "be a monad". For this to occur our something must be three things, a triple
The names are all meaningless so for the moment they just get short letters.T must be what's known as a Functor. For PLs really, though, it's even more specific. It's an "endofunctor on the type category of your language". What this means is simple
* For any (static) type `a` in your language, `T a` is also a static type.
* For any function `f` from type `a` to type `b`, `T f` is a function from type `T a` to `T b`.
If your language doesn't have static types then you can approximate this by pretending that it does. Also note that `T f` is not usually the syntax used, but it'll do for now.
Now to make a monad we take any choice of Functor `T` and give it two operations. `eta` takes values in type `a` to values in type `T a` while `mu` takes values in type `T (T a)` to values in type `T a`. In other words they give you a "layer manipulation toolkit".
They must follow laws as well, but these laws are all "common sense laws" which allow you to think of values in the following types: `a`, `T a`, `T (T a)`, `T (T (T a))`, `T (T (T (T a)))`, ... as all being the same as values with just one layer: `T a`. This is the "flatten" idea.
And there you have it! Anything at all which can be regarded as equivalent to one of these triples following this design and laws is a monad!
---
So the real question is why should someone care? The answer is simple.
Lots of things have monad-nature in a typed language. By recognizing their common nature we can (a) see them in a new light full of perhaps previously unknown similarities, (b) share terminology lightening the burden of how to use them, (c) write generic operations which work over any monad and expect them to work with each specific one in a similar way, (d) introduce new syntactic sugar which is built entirely from (mu, eta) and expect it to work similarly for every thing with monadic-nature, (e) begin to form theories and impressions of "what it means to be a monad".
The reasons (a-d) show up all the time once you recognize this pattern since monads are really common.
Reason (e) is what everyone wants to hear about but it's hard to talk about without being super arm-wavey. But I'll try.
In order to provide the operation `mu :: T (T a) -> T a` the type `T a` must be able to "internalize itself" without losing too much information. In order to follow the laws, one bit of important information is an idea of sequence or nesting—but one unique to each particular monadic triple.
In this way monads are a very, very, very general way of talking about sequencing or nesting.
What makes thins interesting is that you can see imperative languages as being about sequencing or nesting as well. If you have a listing of statements { X ; Y ; Z } then you can see { Y ; Z } as being nested in the execution context that X created and { Z } being nested in the execution context that { X ; Y } created.
This would maybe make you think that imperative languages have monad nature and indeed they do. This leads to an interesting study of questions like "For some given imperative language, what is a pure-functional representation of the monad representing it?" which sometimes has interesting answers.
What's even more interesting is that one example of reason (d) above is to introduce a syntax sugar which makes any monad look a bit like an imperative language. This leads to an interesting study of questions like "What does the imperative language for some monad X feel like?"
So if you really like imperative languages and recognize that there's a larger design space here that most have any familiarity with then monads are a good thing to keep an eye out for.