4 ms·
If you can implement flat_map [0] for something, it's (probably) a monad. You might as well call monads FlatMappables. That's the simplest, most understandable
by pka 7y ago
If you can implement flat_map [0] for something, it's (probably) a monad. You might as well call monads FlatMappables.
That's the simplest, most understandable and most accurate explanation for an initial intuition I've come up with so far.
[0] https://apidock.com/ruby/Enumerable/flat_map https://apidock.com/ruby/Enumerable/flat_map
- lmm 7y agoIt needs to be associative. More concretely, if you want to have something like "do notation" that makes sense, so that you can write code like: 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.
- pka 7y agoSure! But note I said "initial intuition". return/pure and monad laws can be explained later, once one understands that there's really nothing magical about monads.
- lmm 7y agoOf course there's nothing magic. But I think it's important to grasp the definition as a whole rather than thinking monads are "just" some subset or superset - the full definition of a monad is quite short and every part of it is vital, even if it doesn't seem so to start with.
- zzo38computer 7y agoIf you have a macro then something like "do notation" could be done in a superset of JavaScript, such as something like this: 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.
- jerf 7y agoThe problem is that being "flatmappable" very strongly implies that it's a container, but it doesn't have to be. It especially privileges the list implementation over other things. It's much the same as saying "Iterator may be a bit difficult to handle, but it's basically a way of presenting the elements of an array one at a time"; it isn't that that statement is wrong, it's that it is incomplete, and really leads people to thinking that iterators can only iterate on things you concretely have in memory, when instead they can iterate on anything (integers in sequence being popular), and there's also an "advanced mode" where you can drive the iterator (frequent example: an iterator to walk over files on the disk that can be fed back to to not descend into a particular directory upon inspection) that you'll never understand if you see iterators as "a way of walking an array". You can understand flatMap and still not really understand "Monad", just as you can understand array iteration and still not necessarily understand "Iterator".
- pka 7y ago> The problem is that being "flatmappable" very strongly implies that it's a container 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.