That's the simplest, most understandable and most accurate explanation for an initial intuition I've come up with so far.
That's the simplest, most understandable and most accurate explanation for an initial intuition I've come up with so far.
x <- f(a)
y <- g(b)
z <- h(c)
for composition, then it needs to be the case that x.flatMap(a => f(a)).flatMap(b => g(b)) is equivalent to x.flatMap(a => f(a).flatMap(b => g(b))). Unfortunately people sometimes implement a flatMap where these are almost, but not quite, equivalent, which leads to very confusing behaviour and subtle bugs.You also need to be able to "point" a pure value and have the equivalences you'd expect - this often ends up being important as e.g. the base case of a recursive function.
const listMonad=(m,f)=>[].concat(...m.map(f));
const x=listMonad*>{
let a=yield [1,2,9];
let b=yield [3,4,5,7];
return a-b;
};
Such a code can then be compiled into a ordinary JavaScript code.You can understand flatMap and still not really understand "Monad", just as you can understand array iteration and still not necessarily understand "Iterator".
Can't fully agree with that, although I see your point. "Mappable" doesn't imply a container more than Functor's fmap method implies that all functors are containers. And "flattening" something is basically Monad's join.
But still, even if "FlatMappable" has a strong container connotation, I think it's good enough for establishing a first intuition. I think that once one shows what flatMap looks like in terms of e.g. Promises, the notion that it's about arrays or containers will vanish pretty quickly.