Hello!
I have a question regarding use and the "pyramid of doom". In the Gleam tour this example is presented:
pub fn with_use() -> Result(String, Nil) {
use username <- result.try(get_username())
use password <- result.try(get_password())
use greeting <- result.map(log_in(username, password))
greeting <> ", " <> username
}
The use edition is of course much more readable than the equivalent use of nested cases, but it only works because the three functions all return the same error type in their results (in this case String). If I were to change get_password() to return Result(String, Int) for example, I get the following error:
error: Type mismatch
┌─ /src/main.gleam:8:3
│
8 │ use password <- result.try(get_password())
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expected type:
Result(String, String)
Found type:
Result(String, Int)
I understand the error, but I foresee situations where you would want to call different functions that have different error types and aggregate any error to a new error. I don't want the nesting required by consecutive case expressions.
I generally don't like the try/catch program flow, but in TS I would handle it like simply this:
try {
// ...
} catch (e) {
throw new AuthenticationError(e.message);
}
I don't really know how to express the same in Gleam. The best I could do to avoid the problem is to use result.try_recover inside the result.try, but that is pretty unreadable:
use password <- result.try(result.try_recover(get_password(), fn(_) {Error("oh")}))
In my example I could of course make sure to return the same error type in the three functions, but perhaps one of the function calls is not my own function.
How do you approach problem? Is it a problem at all (I have no practical experience with Gleam)? Should I just handle the error case that may arise in each function and return a unified error type?
Thanks in advance 🙂