Monads have no relation whatsoever to boilerplate reduction besides the fact that if you (a) notice their existence and (b) operate in a language with powerful enough generics then you can factor that common pattern to reduce boilerplate using that generics support.
If you recognize monads exist and don't have generics support you can still use the concept to better analyze your code and seek out ways of layering in new effects if desirable. You just won't reduce the boilerplate. This is the case with most languages which implement monads as a library, javascript, ruby, clojure, erlang.
I give up.
Also, quite honestly, your claim that monads have no why makes me strongly question your understanding of the subject matter. Also see Einstein: http://www.brainyquote.com/quotes/quotes/a/alberteins383803....
I thank you for your efforts, but can only ask you to reconsider your approach.
Why do we speak of them, as opposed to just combining things in that way when we happen to? Partly, for the reasons people generally speak of design patterns: it's one fewer degree of freedom in your design which makes it easier to reason about and when others know the pattern it is easier to communicate what you are doing to them. In one-off cases, in most languages with (comparatively) limited powers of abstraction, this is most of what's useful about saying "hey, that's a monad!".
In Haskell, "Monad" is also an interface for things that fit that pattern, and we have a lot of functions that operate against that interface to do useful things, so that we don't need to rewrite those things for each new thing that happens to be a monad.
For instance:
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
which is like map, but takes a function that returns a monadic value instead of any function, and instead of producing a list of those monadic values it stitches together the values and gives you a wrapped list of the values. To drive intuition, we can specialize this for a few individual monads: mapM :: (a -> Maybe b) -> [a] -> Maybe [b]
Maybe. Pass it a function that may fail, and a list of values to feed into that function, and it will give you "Just" a list of the results or "Nothing" if any function fails. mapM :: (a -> Identity b) -> [a] -> Identity [b]
Identity. As you would pretty much expect, this is isomorphic to map. Not a lot of reason to do this unless you've got some other function you care about which is expecting something of this form and you want to basically pass map. mapM :: (a -> [b]) -> [a] -> [[b]]
List. The list monad is for nondeterminism - "take every path". I... don't immediately see a good use for mapM in list - something like concatMap is much more useful - but if you ever have a need for it... mapM :: (a -> IO b) -> [a] -> IO [b]
IO. Pass in a function that returns an IO action, and a list of parameters for that function, and give back an IO action that produces a list of the results. A simple example: mapM (\ l -> putStr (l ++ ": ") >> fmap (l,) getLine) ["height", "weight"]
This would have the type IO [(String, String)]
and would, when executed, prompt the user for height and weight in turn, and return a list of tuples containing both the label and the response. You can see how you could trivially add "age". mapM :: (a -> State s b) -> [a] -> State s [b]
State. State actions operate on an additional piece of data that's carried around and threaded through the chain of binds. This specialization of mapM takes a function that produces actions which use or modify state, threads them together into one big such action. mapM :: (a -> Parser b) -> [a] -> Parser [b]
Parser, from the wonderful attoparsec. Here, we pass in a function that generates parsers, and a list of inputs to that function, and get a parser that parses a list!There are a ton more similarly abstract, comparably useful functions, some of which are in http://hackage.haskell.org/package/base-4.6.0.1/docs/Control... - and you can always write something new when there's a pattern you want to exploit for which a combinator doesn't exist. All of this - both the implementations of the monads (except the internals of IO) and the functions that operate on them - is written in ordinary Haskell. You can check out the source on Hackage, if you're curious as to how.
mapM is implemented:
mapM f as = sequence (map f as)
If we inline sequence, that becomes: mapM f as = foldr k (return []) ms
where
k m m' = do { x <- m; xs <- m'; return (x:xs) }
We can strip out the do notation: mapM f as = foldr k (return []) ms
where
k m m' = m >>= (\ x -> m' >>= (\ xs -> return (x:xs)))
where it should be somewhat apparent there's not actually any voodoo.
I literally have no idea what any of that means. It does not seem in any way to explain why you disagree with my understanding.
For example:
> They exist whether or not you reorganize your code.
This seems like the definition of a non-sequitur to me. Replacing a few words, this sentence reads to me semantically the same as
"Anonymous subroutines exist whether or not you reorganize your code."
A true statement, but not one that conveys any previously unknown meaning.
Also please note that nothing you said addresses the WHY of monads.