* almost the same to IO, because of recursive thenable assimilation, something that was added to promises but is totally short-sighted and unnecessary; and because promises are eager which means they don't represent the action to be executed, but the value of an already executed action
For example, an array can be a monad if we define a bind method as map + flatten
Array.prototype.flatMap = function(f) {
return _.flatten(this.map(f))
}
which works like so: allArticles = authors.flatMap(author => author.articles);
return would be Array.of = function(val) { return [val]; }
The shape (type) is the same:the promise's bind (then) method takes a function that takes a value and returns a promise, and returns another promise
the array's bind (flatMap) method takes a function that takes a value and returns an array, and returns another array
the promise's return (Promise.resolve) method takes a value and wraps it in a promise
the array's return (Array.of) method takes a value and wraps it in an array.
You can get the array method types (shapes) from the promise ones by replacing promise with array (if you decide to give the methods the same name).
The implemented functionality, however, is vastly different.
Haskell is great because it's type system is rich enough to represent these concepts and not only that but enforce their usage (to a degree). Unfortunately this is like a drug, once you get a good dose of Haskell it's easy to crave an even richer type system with dependent types.
And then you can go much further into that world with the scalaz library.
One of those things was Scala's `for` (and `flatMap`). It clicked for me once I noticed how similar it was to Haskell's `do` notation for Monads.
What's surprising to me is that it would seem Haskell has no right to be this helpful for understanding production code!
https://www.google.fr/search?q=jvtoups+monads
I hope you know lisp just enough to adapt to the lisp-1 lisp-2 namespace.