3 ms·
I love monadic error handling too, but not for the reason that the author cited. The fact that you know exactly what errors a function can throw is not an uniq
by raphaelj 11y ago
I love monadic error handling too, but not for the reason that the author cited.
The fact that you know exactly what errors a function can throw is not an
unique feature of monadic errors: in Java, you are required to explicitly list
exceptions that a function can throw (checked exceptions), and you must handle
every exception when calling the function.
The real feature of monadic error handling is that error handling become
composable.
Imagine that you want to write a function that accepts three character-encoded
integers and that you want this function to return the first integer it
successfully parsed.
With exceptions, you will probably use a parseInt function with a type similar
to:
fun parseInt(String) -> Int throws ParseException
And you will write the function like this:
fun getFirstInt(String a, String b, String c) -> Int throws ParseException:
try:
return parseInt(a)
catch e1:
try:
return parseInt(b)
catch e2:
return parseInt(c)
Now take a language supports algebric data types (like Haskell, Rust, Scala or
OCaml). The parseInt function will probably have a type similar to:
fun parseInt(String) -> Result<Int, ParseException>
You will probably define a simple operator to manage the pattern if it fails,
try that instead before implementing the getFirstInt function. Lets call this
operator <|> (it's its name in Haskell):
fun operator <|>(Result<r, e> left, Result<r, e> right) -> Result<r, e>:
match left:
Ok(r) -> return Ok(r)
Error(e) -> return right
With this operator, getFirstInt could be implemented as simply as
fun getFirstInt(String a, String b, String c) -> Result<Int, ParseException>:
return parseInt(a) <|> parseInt(b) <|> parseInt(c)
I think that the fact that you can write you own error handling operator is the
killer feature of monadic error handling (and monadic programming in general).
It makes the enforced handling of errors really painless (while it's like hell
in Java where every exception must be handled).
It's almost impossible to create this kind of operators with exceptions because
they are not a return value, and thus can't be handled in expression. With
monadic error, handling operators are just plain old functions.
- masklinn 11y agoJust a note, Rust's error handling is not monadic because Rust doesn't have monads because it doesn't have HKTs, I guess we could call it "reified" though.
- GolDDranks 11y agoActually it is. Rust Option and Result types implement .and_then(), which is equivalent to bind. They are also equipped with many of the other things you'd expect of a monadic types. The thing is, Rust's type system is currently incapable of expressing an GENERAL monadic trait/interface, which it would be, if it had HKT. (That would allow implementing all the additional monadic util methods as trait default implementations, and having generic functionality applying to any monad.) Hopefully we get there someday.