I finally got my head around monads once I understood how they are useful in c++/python by allowing you to chain together functions of the form T -> Generic<U>
. For example, if you have
readfile = [](string s) -> optional<string> {...};
http_request = [](string s) -> optional<int> {...};
inverse = [](int i) -> optional<int> {...}
then bind >>= :: optional<T> -> (T -> optional<U>) -> optional<U>
has exactly the right signature to allow you to compose these functions
optional{"myfile"} >>= readfile >>= http_request >>= inverse;
// or in haskell
read_request_inverse = (>>= inverse) . (>>= http_request) . readfile
instead of writing out the short circuiting conditionals by hand
[]() -> optional<int>
{
auto message = readfile("myfile");
if (!message)
return nullopt
auto number = http_request(*message)
if (!number)
return nullopt
return inverse(*number)
}
I think what tripped me up was not distinguishing chained binds from nested binds (which Bartosz Milewski demonstrates with c++ ranges) and understanding them separately
auto triples =
for_each(ints(1), [](int z) {
return for_each(ints(1, z), [=](int x) {
return for_each(ints(x, z), [=](int y) {
return yield_if(x*x + y*y == z*z, std::make_tuple(x, y, z));
});
});
});
which is just list comprehension
triples = [(x, y, z) | z <- [1..]
, x <- [1..z]
, y <- [x..z]
, x^2 + y^2 == z^2]
Also I believe I got tripped up on the fact that the reader, writer, and state monads are just trying to reverse engineer side-effects (which I'm not entirely sure doesn't reintroduce the problems of impure procedures/subroutines) and so aren't useful in multi-paradigm languages where you can just have real (sensibly constrained) side-effects.
So monadic optional<T>
/result<T,E>
seems highly useful in c++/python/rust, and monadic ranges/lists might be useful solving coding challenges but not really for real life problems (edit: I've actually started using flatmap
/views::for_each
it a lot for simplifying "business logic").
So my question is are there any other examples of monads that can justify the usefulness of monads in multi-paradigm languages?