4 ms·
"That's silly because the benefits of this type of programming can't be grokked until you use it on real projects.. it's honest-to-goodness not enough to look a
by jerf 7y ago
"That's silly because the benefits of this type of programming can't be grokked until you use it on real projects.. it's honest-to-goodness not enough to look at small examples and judge whether it's worthwhile or not."
But you can look at small examples and decide that the syntax noise isn't worth it.
It's almost always a good idea to write "$LANGUAGE in $LANGUAGE" and not write "Fortran in $LANGUAGE" or "Haskell in $LANGUAGE". Importing these idioms into JS is pretty much the latter. You pay costs you don't pay in Haskell, and you don't get advantages that you can get in Haskell. It shouldn't be a surprise that the cost/benefit analysis for the constructs in JS can result in a very different one than the one for Haskell. You can't just substitute the analysis for Haskell and assume that it's all the same everywhere else.
It's not "elegant". It's importing what is an elegant idiom in another language into a language where it's klunky, poorly-supported, and contrary to the grain of the language. It isn't elegant in JS just because it's elegant in some other language. It's exactly what it looks like: a klunky, choppy way to program in JS that requires the creation of a ton of functions that only a few outliers would normally think deserves its own function, making following this code require a lot of jumping around in the code base.
And that's assuming it is what it says it is, which, as near as I can tell, it isn't. If I'm reading this right, it doesn't seem to properly short-circuit on errors properly, rather doing a rather odd thing where it tries to pass the value along down the line, which is at the very least going to have performance consequences and almost certainly major correctness consequences as this scales up. It's actually not even an implementation of "monad", but a sort of chopped up version to try to avoid creating even more functions, which is what is really necessary to correctly implement the "monad" interface. In Haskell do notation, every single "<-" is actually an entirely new function, nested inside the previous one, so:
do
thing <- whatever1
morething <- failableLogic arg thing
things <- mapM stuff [thing:arg2]
return head things
If "failableLogic arg thing" fails, that function ends up returning, and the next two lines "don't execute", that is, the nested functions don't ever get invoked. The "return head things" is actually a function nested in a function nested in a function nested in a function. (I may be off by one.) I think the core reason there's a lot of blog posts about how to "implement monadic stuff" in all kinds of other languages and no code in the wild that actually uses any of it is the requirement for all the nested functions. (You usually can't "unnest" them either due to the fact you're almost always closing over values from the previous functions.) It is astonishingly inconvenient in languages that don't have the requisite features and support, to the point you can fairly reliably guess that if someone has an implementation that isn't staggeringly inconvenient to use, they've missed something fundamental.
Even the languages that sorta kinda support this, don't, really. They encode specific bits of functionality vaguely inspired by monadic handling, but out of the Haskell family of languages I don't think I've yet seen a full, true implementation of "monad" in general that anyone uses.
(When writing "$LANGUAGE in $LANGUAGE" isn't adequate for a task, it's almost always the right answer to go get a new $LANGUAGE.)
- 0815test 7y ago> In Haskell do notation, every single "<-" is actually an entirely new function, nested inside the previous one ... The "return head things" is actually a function nested in a function nested in a function nested in a function. (I may be off by one.) I think the core reason there's a lot of blog posts about how to "implement monadic stuff" in all kinds of other languages and no code in the wild that actually uses any of it is the requirement for all the nested functions. This "nested functions" pattern is precisely what promises/futures/async-await does. It's just a different way of expressing the same things - "promises" are just continuations, which are as general as do notation itself.
- dakom 7y ago> Even the languages that sorta kinda support this, don't, really. They encode specific bits of functionality vaguely inspired by monadic handling, but out of the Haskell family of languages I don't think I've yet seen a full, true implementation of "monad" in general that anyone uses. I just updated the links to FP-TS and Sanctuary... have you checked those out? They seem to tick all the boxes as far as I can tell.
- esarbe 7y agoScala's for-comprehension work quite good. It is part of idiomatic Scala and works for all monads. for { thing <- whatever1 thing2 <- mightFail } yield (thing, thing2)