|
I always see monad tutorials like this conflate (1) "understanding using particular monads" with (2) "understanding using monads in general", which are completely different things. Luckily it's easy to not confuse those two with (3) "understanding monads abstractly" which tends to break out the category theory, but some tutorials like jumping on that too. To demonstrate the differences, suppose now that you're deep diving into a codebase which depends on a Async monad. Your eyes light up and you go aha(!) that means async programming, I've done that before! The point is, you saw "Async", you know it means "make some task's outcome depend on a previous task", which is the behavior of bind for that particular monad. Without (1) the word "monad" is really unnecessary. Why not just refer to bind as some arbitrary async-API function? In summary, you don't need (1), (2), or (3) for this! Monad is just a word. Okay, when do we need (1)? Let's say you've changed companies, and now you're plugged into another codebase and oh(!) there's that word "monad" again, but this time it's the "Future" monad. Another whole API to learn... but soon you realize that it's again the same old "make some task's outcome depend on a previous task". Except they just call it "Future", and instead of "bind", they say "flatMap" which is the same thing! And you bump into it again and again with different names -- Deferred, Aff, Task -- but in the end it's the same behavior and API. How upsetting that they don't call them all Async and be done with it! But if you have (1) you'll know they are just the same monad, given different names. That's (1): familiarity with the usage of a particular monad. Later on you might collect understanding of the Option/Maybe/Nullable monad, or the Result/Either/Error monad, or the List/Stream/Nondeterministic monad, so now names don't bother you because you know CONCEPTS, but all of this is still (1) if each monad is being treated as an independent API to grok. That's where (2) comes in. Suppose now that you're deep diving into a codebase which depends on the "Anisotrope" monad. You've never heard of this before[0], but you know monads in general i.e. (2), so you know you can make functions whose output (an Ansiotrope object) depends on some property of a Ansiotrope object, and that all the details about this dependency can be found in the definition of bind for this particular monad. In other words you can use knowledge of (2) to quickly adapt to new monads without having to regard them as a completely new concept. It lets you answer questions like "what's this Probability monad supposed to do? what about this Forkable monad?" in a general way. Conversely, you can now start writing monads of your own by thinking about what bind could mean for your new "Transmogrifying" monad. Is this useful? Imagine learning all OOP patterns knowing that every pattern is the same concept except for this one thing: bind. That means it's relatively trivial to learn these patterns and make new ones. Except they're not OOP patterns, it's monads, and no, you can't generalize OOP patterns the same way. Anyways, this is also where "monad is a box"-esque metaphors fall short. It's rather descriptive of particular monads, but doesn't generalize well when you start reaching for many others: Reader(environment-passing), List(nondeterministic computations), Probability(probabilistic programming), or fun ones like parser monads, Amb(backtracking), Tardis(state-access-timeline-specifying)[1]. [0] I hope not, since I made it up. If you have (3) you're probably deriving a working definition already. Have fun!
[1] http://hackage.haskell.org/package/tardis-0.4.1.0/docs/Contr... |
> Imagine learning all OOP patterns knowing that every pattern is the same concept except for this one thing: bind. That means it's relatively trivial to learn these patterns and make new ones. Except they're not OOP patterns, it's monads, and no, you can't generalize OOP patterns the same way.
From the OOP perspective, though, monad is a pattern where you only have one behavior (bind) that you can customize, and you have to do everything through that one behavior. That looks like a straightjacket. Sure, it composes well, but... why limit yourself like that?