4 ms·
It can still help save you time where you would normally use an exception. If I only want to continue the current operation if no exception is thrown, I can use
by nv-vn 11y ago
It can still help save you time where you would normally use an exception.
If I only want to continue the current operation if no exception is thrown, I can use a function I've written without any exception handling by using a functor:
return readFromFile("file.txt").map(text -> parse(text));
In this case, I'm only going to parse the contents of the file if they exist. Normally, I'd have to write:
try {
return readFromFile("file.txt");
} catch (SomeFileException e) {
// Handle it
}
Of course, the top one lets you handle it up-stream, but the specific thing about using types instead of exceptions is that you're forced to handle it at some point, but that doesn't mean you have to write substantially more error-checking code.
Now with a monad, I can do the same kind of abstraction even more powerfully. Say I have a function that may return an exception and I want to run that over the file:
return readFromFile("file.txt").bind(text -> writeToFile("some_other_file.txt", text);
In this case, writeToFile could fail. If it does, it's going to return Nothing. Otherwise, it returns Just (the text we wrote). Now, if we were to just use .map() here, we would end up with Maybe<Maybe<String>>. We don't want that, that's redundant information. It either failed, or it didn't. In order to help us out, the .bind() function consolidates the two Maybes into one Maybe, so we get back a Maybe<String>. Here is where monads really pay off: with exceptions, we'd have to handle them at multiple levels, but using .bind() we're able to only handle them once (by checking in our main function, for example, what we got back from the entire process).
If we read the definition of bind here, it's a lot more clear (here I'm specializing the return types for more clarity, but in Haskell it'd be a more generic definition):
Maybe<String> bind(Function<String, Maybe<String>> f, Maybe<String> x) {
switch (x) {
case Just(theString):
// Notice, we're not returning Just(f(theString)).
// We let f() determine whether we return back something
return f(theString);
case Nothing:
return Nothing;
}
}