Hacker News new | ask | show | jobs
by ColonelPhantom 693 days ago
By simulating exceptions, do you mean a `Result t e` type (which Haskell calls `Either l r`)? You can use these and the Functor/Applicative/Monad hierarchy to handle errors.

What is presumably talked about is that Haskell also has actual exceptions, generated by calling e.g. `error` or `undefined`.

The semantics of these are.. interesting, mostly thanks to lazy evaluation. For example, `fst (5, error "second") ` is safe to evaluate because the second half of the tuple is a thunk and does not get evaluated. Additionally, there is, to my knowledge, no way to handle exceptions in pure code, presumably due to the undefined evaluation order.

That said, I'm not sure what the alternative would be, because a function like !! (list indexing) can fail and dealing with its fallibility would be a big burden on the programmer.

1 comments

> By simulating exceptions, do you mean a `Result t e` type (which Haskell calls `Either l r`)?

Yes, exactly.

> The semantics of these are.. interesting, mostly thanks to lazy evaluation. For example, `fst (5, error "second") ` is safe to evaluate because the second half of the tuple is a thunk and does not get evaluated

Correct, and the semantics of loops is also.. interesting. For example `fst (5, last [1..])` is also safe to evaluate.

> What is presumably talked about is that Haskell also has actual exceptions, generated by calling e.g. `error` or `undefined`.

Well, I'm not sure, that's why I asked. I'm trying to understand what astrange meant by "it has exceptions which are a bad language feature, and typed throws which are a worse one". (Throwing exceptions from pure code should be left to such cases, that are impossible to recover from, in my opinion.)

> there is, to my knowledge, no way to handle exceptions in pure code, presumably due to the undefined evaluation order

Correct

> That said, I'm not sure what the alternative would be, because a function like !! (list indexing) can fail and dealing with its fallibility would be a big burden on the programmer.

Indeed. Even more so, what is one supposed to do when an invariant has been violated due to a programming error and there's no way to make progress? Haskell's exceptions are essential. It's even better when they're used in a well typed, well scoped manner, such as provided by my effect library Bluefin

https://hackage.haskell.org/package/bluefin-0.0.6.0/docs/Blu...

That's why I wanted to understand more about what astrange meant. It doesn't match my understanding!

Hm yeah, I'm not sure what astrange's point was, other than probably dissatisfaction with the combination of exceptions and Either (which I think is awfully named, as it implies a certain 'equality' between l and r).

I haven't used Bluefin, but don't Bluefin exceptions suffer from the same issue where it, essentially, 'infects' the program flow? For example, `fst (5, error "second")` seems like it would translate to `fst $ (5,) <$> throw e "second"`, where you would also need to pull an `e` from somewhere. More realistic, something like head would probably be quite awkward:

head e [] = throw e "head: empty list" head e (x:xs) = pure x

You now need to pass in the exception handle, and the return value is now `Eff es a` instead of `a`. This means that you cannot just use the result, so you will likely need to fill your program with monadic stuff like do-notation, <$> and <$>, complicating the program flow and likely also reducing laziness.

You're right, but my response would be that

    fst (5, error "second")
and

    head [] = error "empty list"
    head (x:xs) = x
are simply not things you should be writing. They're not good program design and it's not a weakness that Bluefin doesn't support them unaltered.