Monads are used virtually everywhere in software engineering. We are not always aware of them. But wherever you are using lists, errors, state, parsers, futures, I/O, or random number generators, chances are good that you are making use of the fact that these things form monads.
The basic functionality provided by all monads (and therefore the reason to use them qua monads) is substitution and normalization. The basic thing that a monad allows you to do is variable assignment and to substitute subexpressions for variables. The monad then re-normalizes the expression to a new one that has your subexpressions grafted where the variables used to be. Each monad carries some effect and the renormalization procedure (the monadic join, or the natural transformation µ) determines how the effects are combined.
For example, in a list of integers you can view each of them as a variable. Then if you have a function from integers to lists (of type
Integer -> List x), you can substitute a list of values of type `x` for each of the integer variables which gives you a list of lists. Then you remove the inner brackets (normalize) to end up with a plain list where each of your integers has been replaced by zero or more elements of type `x`. Here's that in action:
i <- integers
r <- numberwang(i)
} yield r
With an error monad, you will have some expression `e` that is either an error or a value. You can view that value as a variable and substitute another expression `f` (which could also be an error) for the variable. When the monad renormalizes you get a single expression `g`. If `e` would have failed, then `g` fails with that error. Otherwise it fails with `f`'s error, or succeeds if there were no errors. Example:
i <- mightError
r <- mightAlsoError(i)
} yield r
We could repeat this pattern for all monads. But the real power comes from the fact that we can abstract over the monad and write programs that don't just work with lists, or just with futures, or just with errors, but with any monad. They all share a common interface that we can exploit and program against. In practice there is an enormous library of functions that can be written once and for all, and reused for any given monad. And since monads are everywhere, this is very useful.
For the category theorists, the monads that are used in software engineering are specifically (usually) the monads on Set.