
Exceptions are convenient in that you can rely on libraries throwing them instead of prechecking for valid values yourself (for instance, why check that the argument to Char.digitToInt is valid if digitToInt does so already), and you don't have to modify a lot of function signatures. Unfortunately, in the face of lazy evaluation, they can get thrown in unexpected places. Even with Exception.evaluate, or code which is already explicitly sequenced in the IO monad, like "t <- Exception.evaluate (map Char.digitToInt ['a'..'g'])" an exception will only be thrown when you inspect the last element of 't'. (digitToInt confusingly accepts hex "digits"---shouldn't it be "higitToInt" then?). So it seems to me that if you are, say, checking input, the options are to handle exceptions from the checking code but expect them to come from the processing code, or decorate all checking code with Rights and Lefts. Problems with the first option are that checking code could also trigger some exceptions, and Prelude functions throw undescriptive errors like "user error" or low level ones like "refuted pattern match" and catching them over the entire program means you could stifle a lot of real errors. This implies that you have to make specific exceptions and convert Prelude and library exceptions into yours as low down as possible, which is cluttering but maybe not as cluttering as Either. Problems with the second option are many of the problems that lead to us wanting exceptions in the first place. Using Either seems much simpler and functional-friendly. So then, in what contexts are exceptions appropriate in haskell?