I think a lot of the problems with monads is that they're way too low level to really get a grip on what they're for --- it's like trying to explain algebra by talking about manipulating pixels on a screen.
Once I finally saw some of the things you can do with a monad rather than those useless examples based around Maybe, I had an 'aha!' moment as everything went click.
A monoid is a type where we know how to combine two elements together. There are two parts: a function that combines and an identity for it. (The function is usually written as an infix operator to make it easier to read.)
For example, we can combine two integers by adding (+) with 0 as an identity. Or we could combine them by (*) with 1 as an identity.
Lists are a monoid because we can append two lists and the empty list is the identity.
The combining operator has to be associative and the identity has to be an identity for it. (Combining something with the identity gives you that original thing back.)
And that's all. There's just not much structure to them. In fact, there's so little structure that mathematicians don't care much about them. It's an exotic-sounding name for a fairly pedestrian concept.
But they're useful in programming. The main reason is that they're so ubiquitous: so many different things form monoids, often in different ways. This means we have a single interface applicable to almost every domain you can think of which is useful even if the interface doesn't tell us much.
They're also a good fit for parallelism. Because the combining function is associative, we can a bunch of combinations in any order we like, making it easy to spread them out over multiple threads. It very naturally captures the reduce in map reduce.
But mostly it's a convenient abstraction that's minimal and simple enough to pop up everywhere while still being useful.
Monoids are much easier. You just need a binary associative operator |+| (+,*, min, max all work for ints, ++ for lists/vectors, for instance) and some notion of an identity for the type s.t. forall a: A, a |+| identity === identity |+| a === a
They are HUGELY useful. One of the most useful is a "union" monoid definition for Maps. In Scala, it's written like this:
So any map with Semigroup values is a monoid (Semigroups are monoids without the zero value). |+| under this definition will combine the Maps, but in hte case of collisions, |+| the colliding values together. This Monoid is the ABSOLUTE KING of aggregation. You can foldMap over lists and produce singleton Maps of the shape you want, and let the monoid instance aggregate for you.
Monads are neither low- nor high-level. Monads are orthogonal to this. A monad (in the context of programming languages) is a generalised from of function composition. Instead of composing f : A --> B with g : B --> C yielding a function g;f : A --> C, monads compose functions f : A --> FB with g : B --> FC, yielding g;;f : A --> FC. Here F is come transformation on types. Monads connect the types FB and B in a canonical way. That's all.
Apologies in advance for the unsolicited monad tutorial (it's my turn to be that asshole)...
Firstly, saying "`X` is a monad" is the same as saying "class `X` implements the monad interface".
The monad interface is usually defined with `return` and `bind`, but I think it's more instructive to borrow the terminology from JavaScript's `Promise`...
* `Promise#resolve(value)` is the same as `return`, also known as `pure`. It just wraps the given value in a promise.
* `Promise#then(function)` combines both `bind` (when a new Promise is constructed and returned) and the functor method `map` (when a plain value is returned).
To provide a unified monad/functor interface for both `Promise` and `Array` (using `wrap` instead of `resolve):
// `then` provides both `bind` and `map` depending on the return type of the given function:
Promise.prototype.map = Promise.prototype.then
Promise.wrap = Promise.resolve
// f maps elements to arrays of elements:
Array.prototype.then = function (f) {
return [].concat.apply ([], this.map(f))
}
Array.wrap = function (x) {
return [x]
}
There's no intrinsic value beyond that shared interface, it just allows you to write abstractions without knowing specifically what kind of monad you're dealing with (like the "do" syntax).
EDIT: BTW, I've purposely skipped a few things in this description, it's meant to be illustrative, not definitive...
I think using Haskell's type syntax is misleading in this context (and doesn't really imply the required associativity (much less commutativity if you wanted to consider Abelian monoids)).
The operation of a monoid maps from pairs of things to things. So in terms of types:
<a,a> -> a
Or for some `twin` type constructor:
twin a -> a
This is a bit more suggestive also in terms of F-algebras, where the operation has the following signature (f is a functor, or mappable container):
There Haskell people go again =) You try to define something in simple normal terms, and off they go adding highly specific and technically correct words to what was supposed to be a simple explanation.
(I'm not a Haskell expert, I dabble, done CIS194, half of RWH, and I have no idea what you said -- which is a common problem I run into in the Haskell world, lots of super helpful people that have forgotten what its like to not speak their language)
I'd sort of like to see 'return' explained earlier, rather than used without explanation in the IO monad example. Also it's weird to hear that a monad is a design pattern, and then hear about the monad deciding things; that implies something more concrete than just a design pattern. It's only vaguely clear that "the monad" in that sense is the specific choice of bind/return functions (if that's even correct!). But while it's a bit rough around the edges, I can see this becoming a really good explanation. It explains how the goals of monads relate the implementation, which seems to be the tricky part, in a way that makes sense to me.
Once I finally saw some of the things you can do with a monad rather than those useless examples based around Maybe, I had an 'aha!' moment as everything went click.
No sodding idea what a monoid is, though.