3 ms·
Hey thanks for clarifying -- Maybe I've just been a victim too long, but those actually don't seem like distinct ways. As far as why you can throw an exception
by hardwaresofton 9y ago
Hey thanks for clarifying -- Maybe I've just been a victim too long, but those actually don't seem like distinct ways. As far as why you can throw an exception in pure code but only catch it in monad, much ink has been spilled[0]. I won't claim to completely understand the reasoning in that SO post and the linked paper[1], but the reasons for this dichotomy seem to be clear.
2) -> 5) are not ways of handling errors though, they're ways of characterizing/combining monadic computations that CAN error, IMO. In the end, it's still the errors-as-values (`Either SomeException value`) concept, but in combined with the fact that your computation is in a monadic context. Also, maybe I've just been brainwashed by myself to think that way after doing Haskell for this short amount of time.
In practice, how I throw an error from a monadic computation (I generally have never done it from pure code) has been pretty well-defined, I haven't had to go down this particular rabit hole much at all -- ExceptT is what I've used the most (I've done most of my work with Servant[2]). Honestly what I've had problems the most with from my haskell code was dealing with the database or mail servers and tcp sockets and stuff -- stuff that failed at runtime because I put in some bad code Haskell couldn't check before runtime.
That said, monads & monad transformers are indeed a complex concept, and are very confusing to beginners (I'm still not 100% confident in my knowledge of them), so this is definitely a point against Haskell.
And of course your earlier point about unsafe functions in the std lib is as valid as ever.
[0]: https://stackoverflow.com/questions/12335245/why-is-catching-an-exception-non-pure-but-throwing-an-exception-is-pure#12345665 https://stackoverflow.com/questions/12335245/why-is-catching...
[1]: https://www.microsoft.com/en-us/research/publication/tackling-awkward-squad-monadic-inputoutput-concurrency-exceptions-foreign-language-calls-haskell/?from=http%3A%2F%2Fresearch.microsoft.com%2Fen-us%2Fum%2Fpeople%2Fsimonpj%2Fpapers%2Fmarktoberdorf%2F https://www.microsoft.com/en-us/research/publication/tacklin...
[2]: https://haskell-servant.readthedocs.io/ https://haskell-servant.readthedocs.io/
- gizmo686 9y agoMy only real complaint about exception handling in Haskell is the interaction with laziness. 90% of my problems would go away if they just made the default catch functions include `evaluate . force` and save the lazy behavior for special "I know what I'm doing" functions. Without that, exceptions are just a loaded gun. Even with making exceptions "safe", I still much prefer the error-as-values approach. Otherwise, every pure function is really some type of ExceptT IO monad. I'm sure this escape hatch is useful to someone, but actually using it is a pretty big code smell.
- hardwaresofton 9y agoYeah this is actually an oft-repeated problem. I haven't really run into problems with enforcing strictness but that just means I haven't written/profiled enough Haskell yet, probably. Note though that there is the new Strict pragma: https://ghc.haskell.org/trac/ghc/wiki/StrictPragma https://ghc.haskell.org/trac/ghc/wiki/StrictPragma Also, this isn't really a solution to the problem (at best I'm just being an apologist), but you could write rules with hlint or any other code-smell-checking-tool to make sure no one every tries to use the escape hatch(es) you don't like.
- danharaj 9y agoWe basically ban throwing exceptions in pure code at my shop; usually we use ExceptT or throwIO or something. I used to think the multiplicity of error handling constructs in Haskell was confused and bad, but they all have their uses. The key insight is that your error handling should conform to the local structure of your code, not the other way around. Propagating errors across multiple component boundaries or multiple layers can be cumbersome but I think that reveals fundamental architectural weaknesses in the program itself.