3 ms·
I like this list, although I want to nitpick the use of the word "monad", since it seems to (a) put people off these ideas, either due to them seeming scary or
by chriswarbo 8y ago
I like this list, although I want to nitpick the use of the word "monad", since it seems to (a) put people off these ideas, either due to them seeming scary or pompous/ivory-tower and (b) confuse those who are otherwise receptive to the idea.
Rather than call this "monadic error handling", I'd just say that results are wrapped up so that errors can be distinguished from successful results. Usually that's done by wrapping in a list (or, if the language supports it, an "Optional"/"Maybe" type, which is just a list truncated to 1 element).
Adding this extra structure lets us distinguish things like "the query died" (an empty list) from "there was no match" (a list containing an empty list). If we'd used NULL to indicate failure, we wouldn't be able to distinguish between these situations (or indeed if there was a match, whose value happened to be NULL!).
Naively we might think this require a lot of length-checking and unwrapping, but we can avoid that by using list operations that are (hopefully) familiar to every programmer, like "map", "concatenate" and "singleton".
It turns out that those operations form a monad, but it seems overly dramatic and confusing to name the approach using that terminology. Sure it's nice that we can abstract out this interface, but we don't need that much abstraction when our whole ecosystem is using a single, specific implementation like "Optional".
Incidentally, there's a really nice paper on this called "How to replace failure by a list of successes" ( https://rkrishnan.org/files/wadler-1985.pdf https://rkrishnan.org/files/wadler-1985.pdf ), which shows how normal, non-truncated lists actually implement backtracking search (assuming our lists are lazily generated, e.g. like in Haskell or using an iterator).
Note that being "monadic" specifically means we're able to 'collapse' these lists, i.e. concatenate a list-of-lists into a list ("singleton" comes from a weaker notion called 'applicative', "map" comes from an weaker notion called 'functor'). Collapsing lists removes the distinctions that we introduced, since "concat([[]])" and "concat([])" are both "[]", making our result act more like NULL. So calling this approach "monadic" is actually emphasising the wrong part!
"Do you struggle to track down the source of NULL values in your code? With monadic error handling you can struggle to track down 'Nothing' values instead!"
The real improvement is from the non-monadic interface, like "map", which preserves these distinctions.