top | item 30478035

(no title)

danidiaz | 4 years ago

> If we need to compose these errors in a larger program we can simply wrap previous errors in a bigger sumtype

This approach is being adopted in GHC itself to compose errors happening at different stages of the compilation pipeline: each stage has its own error type which later becomes a branch of the global error type.

Another interesting post about errors-as-values in Haskell is "The Trouble with Typed Errors": https://www.parsonsmatt.org/2018/11/03/trouble_with_typed_er...

discuss

order

codeflo|4 years ago

The GHC approach you describe is also what people do with Results in Rust, and (analogously) with Java's typed exceptions. The idea is that in a multi-layered program, every layer exposes errors that are semantically appropriate for that layer. So (to pick a silly little example) a database call would expose a DatabaseError, not a raw network error if the connection is interrupted. And so on until you get to the level of application-level errors. I think that can work very well.

In the same spirit, I find the article you linked to a bit silly, at least the examples they picked. Following the logic above, there shouldn't even be a "HeadError" exposed anywhere up the call chain. Inventing a complicated mechanism to propagate the error upwards is the opposite of what you want to do; you want elegant ways to handle the problem locally. Having a special singleton HeadError isn't wrong, but I think "Maybe a" would also be a perfectly fine return value for head (as I mentioned in a sibling post, that's what Rust does): head can only "fail" if the list is empty, so there is no actual information in the "error" value.

agentultra|4 years ago

The ‘head’ function is an unfortunate historical artifact and not the norm these days. In practice there are libraries that expose a head function that returns a value… but better still, well typed programs can avoid the need for it altogether: there are non-empty lists to consider in which head is trivially safe to use, provided one can construct such a value.

One error handling strategy not often employed is to prefer code that is correct by construction. It can’t always be done but it’s nice when you can do it.

update spelling

fn-mote|4 years ago

> so there is no actual information in the "error" value.

At least as a beginner, the information about which line the error occurred on would be helpful.

default-kramer|4 years ago

> https://www.parsonsmatt.org/2018/11/03/trouble_with_typed_er...

Nice. I've asked for a way to do that in the past and never found a good answer, in any language! It's not exactly conventional Haskell though, is it? What I really want is first-class support in the language - something like checked and unchecked exceptions in Java, except that if a method declaration lacks a `throws` keyword then all the checked exceptions are inferred by the compiler. For example, the compiler might add `throws A, B, C` to a method that lacks a `throws` keyword. Now if you want to assert that a certain method throws a certain exception, you could write `throws A, *` which means "If this method does not throw an exception of type A, I want a compiler error. If this method throws additional exception types, infer them as usual." Omitting the asterisk (eg `throws A`) would disable the inference and thus would work like a normal `throws` in real Java. You should also be able to assert that a certain exception type is not thrown, for example `throws * except F, G` or something like that.

ParetoOptimal|4 years ago

> Another interesting post about errors-as-values in Haskell is "The Trouble with Typed Errors": https://www.parsonsmatt.org/2018/11/03/trouble_with_typed_er...

At the point of `AllErrorsEver` I usually find throwing an exception make sense. That doesn't negate the use of defaulting to `Either` rather than exceptions for the "leaves" of your tree of code where each defines a sum type of errors at the function or maybe the module level.

Edit: My last recommendation is basically consistent with the article.