3 ms·
Flatland? great book. Surely monads are more than truisms! Forgive me, I must have missed the point.
by sova 5y ago
Flatland? great book. Surely monads are more than truisms! Forgive me, I must have missed the point.
- massung 5y agoLOL. Fair enough. :-) I just find that when I read most people discussing "why monads" it usually degrades into code examples and the OP still left asking "yeah? so? I could already do X? what did that do for me?" Similar to how a C++ programmer trying to tell a C programmer about std::vector might leave the C programmer is just saying "yeah? so? void* works just fine." I was attempting to steer the discussion in a different direction: about taking what you know and codifying it, which allows you to be sure - at compile and/or runtime - about what's happening. To take it back to your original question: > Can someone give me a practical example of when one would want to use a monad? Others have given good examples. But, I'll try and put it into the context of my reply by making up a contrived example. Let's say you have a hash map and want to look up a key's value. The function can return the value stored or a default if the key doesn't exist. But, you can't tell the difference between your default value being returned or the same value already existing. One solution would be to return multiple values, including a boolean indicating whether or not it's the default. But, presumably (since we care in this contrived example), downstream decisions and further data needs to know if the key was present. So, you need to keep passing along both values all the time. After all, per the original reply - any value derived later from the returned value also belongs to the category of "maybe derived from a default value/missing key". Instead of constantly passing around the value, a flag, and maybe even the missing key, you could return and pass around a struct of those 3 values. But, now you have a problem: all the existing functions you want to pass your value to don't understand your struct. Additionally, if you want to remain true to the "truism", those functions need to also return your struct, which they don't. Monads are the pattern created for solving this exact problem. Monads define an interface for... 1. Taking a value and returning your monad type 2. Taking a function (F) and returning a new function that can take your struct, extract the original value from it, pass it to F, and return a new struct with the return value wrapped as well. From there, you get all the other benefits people have discussed elsewhere in this thread "for free". Whether you're working with a strongly typed language like Haskell (and using the compiler to keep you honest) or a dynamic language like Python (and keeping yourself honest at runtime), the problem and pattern holds true. I intentionally picked a goofy, contrived example to stay clear of all the common examples people usually give (futures, IO, errors, option, etc.) to show how you might have a very different use-case that can still benefit.
- sova 5y agoLooking at 2, if F is a delivery-person and my struct is a delivery truck, then the Monad will return a new delivery-person who can take the truck, extract a parcel, pass it to the original delivery driver who will deliver it and the new delivery driver will get the signed delivery receipt, and put it in the truck. Am I getting close or just descending joyfully into madness?