Here’s my shot at a simple explanation of what a monad is in the computer world. First, I have to explain what a monoid is.
A monoid is (roughly) a group of functions who take a parameter of a certain type and return a result of that type.
That’s useful because it allows easy “chaining” or “composition” of functions. Any fluent interface in java is a monoid:
MyThing result = myThing.spin() .treadle() .flip() .invert() .aggregate();
Note that the input to each function is a MyThing, and the result is a MyThing.
A caution; strictly speaking, a monoid needs a few extra things. It needs an “identity” function that just returns the parameter, it needs a binary function that takes two items of the type and returns a new instance of the type, and those binary functions must be associative, so you can change the order of evaluation:
a.do(b).do(c) == a.do(b.do(c))
A monad takes the idea of monoid one step further; instead of mapping a class onto itself, it takes a container type which accepts any underlying type, and lifts that into a monoid space. So it’s a monoid using a container type:
A monad is (roughly) a group of functions who take a container type as an argument and return a result of the container type.
But note that the underlying type of the container may change. So you could map Container<String> to Container<Integer>. But the functions would still line up.
MyContainer<Int> myContainer = new MyContainer(1); MyContainer<String> result = myContainer.<Int>rehash() .fondue() .serializeToString() .prefix() .onomatapeize();
So that you are able to “chain” or “compose” the functions and get a result of any arbitrary type! That’s a pretty strong claim for a statically-typed language like Java.
(Note that in Haskell, the signatures of the functions would be a little different. They would be functions of (Int, MyContainer) or (String, MyContainer), and it would be the job of the container to appropriately apply the function to it’s contents. But it’s hard to make a direct comparison from Java to Haskell, because Haskell works much more directly with function composition. In Haskell, the monad is actually composing the type constructors, rather than with instances of the type.)
But the core idea behind the monad is to create a monoid on a container type, in order to get the benefits of chaining and composition across different underlying types.