One problem I suppose is that not everyone speaks the abstract language of monads and so it does not serve much usefulness, yet, and maybe there is a little chicken and the egg with that.
Well. It's a monad. It's about 30s of work to implement it if you know what you're doing.
Of course, you could implement it as a monad in Javascript as well. It'd be a neat trick, but you'd never love it. The reason is simple: you can't benefit from monads unless you use them so pervasively that everything will integrate together.
And if you do, that integrate together bit works fantastically. People often complain about monads not composing---but I think they're often just misinterpreting a rather technical result. Actually, imo, monads compose incredibly well and it's astounding when you get used to it.
When you use them pervasively, monads mean that you get to "pick your own semantics" on the fly, whenever you want. You can mix and match semantics as is interesting and work with your custom mixes as if they were built into the language.
So people, e.g., talk about how it was easy to write STM because of monads.
It wasn't "because of monads". Of course STM is a monad and anything which looks even halfway like it in any language will also be a monad no matter how hard you try to avoid it. They're "just a pattern".
But when you've got a language which allows you to cut into the "STM monad" exactly and whenever you want, when you've got a hold of the root of the semantics of your language, when you've got programmable semicolons, then there's something really special.
And without that you've got a couple of years of bickering between standards committees to fix what end up being trivial looking problem.s
Exactly. That is what I call mathematical- vs. cognitive-abstraction. They are not the same thing, and in the case of programming languages, only the latter matters. A mathematical abstraction is simply the naming of a pattern; a cognitive abstraction is a human solving a problem by explicitly thinking of said pattern. The former is either true or false; the latter is either useful or not (and the utility is completely orthogonal to any mathematical considerations).
> I appreciate your explanation but again it fails to actually show it being useful outside of the context of working around Haskell's strict type system
I think it isn't useful as a cognitive abstraction (and the problem isn't Haskell's type system, but its purity from effects). I believe that monads as a cognitive abstraction are foreign and harmful to imperative languages, which have an equally-powerful cognitive abstraction -- the thread -- that fits much better with the rest of the language's abstractions and I think is much more useful for most people.
Quoting tikhoni:
> For Maybe, being a monad gives us a standard way of working with values while automatically dealing with Nothing. It abstracts over repetitive null checking and lets us easily build up Maybe values based on other Maybe values.
To expand on that a bit, in a way that might work for you (or might not): I've got a function f a that exists. It works. It does exactly what I want. Unfortunately, the data I've got is a Maybe a, not just an a. So I can't use my nifty function f, because it takes an a. You can feel my annoyance/frustration - so near, and yet so far.
But, in fact, I can use my function f, because Maybe is a monad. That lets me apply f to my Maybe a, without having to change either f or a whatsoever. I don't even have to write the magic code to do this - Maybe already has it.
But seriously, I guess I think it's not a Monad. The Monad signature (in this case) is
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
and I think what we really want (and what I said we wanted to do) is Maybe a -> (a -> b) -> Maybe b
I don't know whether that's Applicative or Functor, but I don't think it's Monad.When I see a bunch of Maybe monads, for example, I can instantly know that the programmer's intent was maybe to not just have a type safe null and avoid null pointer exceptions, but also to possibly make use of Maybe's toxicity.
What I mean by toxicity is you know how in some languages you have "not a number" aka NaN? A NaN times / divided by / added to / subtracted from anything is a NaN, that means that if you have a complex formula, if you throw a NaN in there anyway you get back a NaN. Maybe works the exact same way but with all functions not just arithmetic operators. That's what I mean by its toxicity.
Without Maybe you'd have to explicitly apply that logic everywhere you'd otherwise apply a monadic "join." The reader would then have to study your code much more carefully to understand that intent, and probably look at it with some skepticism that the toxicity works perfectly every time or is in every place you might expect. And of course not everyone values brevity and expressiveness, but when done right it makes code more readable not less, and Monads done right facilitate that.
Maybe's toxicity is just an example of pretty much any "magic" you can build into a Monad. You could for example have a Future Monad that will handle asynchronous control flow for you.
As a side matter, it's not just working around Haskell's strict type system that make Monads a good fit for IO, but also Haskell's non-strict execution.. monads help things happen in the right order which is crucial for IO. That's kind of neat when you think about - the bridge between the mathematical rigor of pure functional code and real world devices that make computing useful. Functional purity makes code easier to reason about and less error-prone.