What is the meaning of exceptions in Haskell? The only usage I see is to put in undefined or error in my code to stop programs from running. Otherwise I consider programming with exceptions as a logical design flaw. But Haskell has an advanced exception module Control.Exception which is used by Prelude. I read that the reason for exceptions in C++ was to prevent a lot of "call function, then check status"-lines in code. But such things can be abstracted away in Haskell. The only other reason I can see for exception handling in Haskell is with FFI, to handle foreign exceptions, but only for internal use in a Haskell function wrapping the call.

There's all sorts of reasons you can get an exception. In an exception-less system what happens when: you run out of memory? The OS sends a signal? You divide by zero? You evaluate a partial function... and discover it is partial! Exceptions aren't a pretty part of any language I know, but in order to cope with the real world they are a necessary part.
–
Thomas M. DuBuissonOct 9 '11 at 17:58

4

Is there a real way to answer this question, or is it just a rant? If it's just a rant, perhaps a blog post would be a more appropriate medium.
–
Daniel WagnerOct 9 '11 at 18:24

1

Yes, for such things there should be possible to stop the program, so we have 'undefined' and 'error' as I said. Divide by zero and evaluating a function "outside its domain" are logical design flaws. But I do not see the meaning of using exceptions in the mechanics of a program (in Haskell).
–
telephoneOct 9 '11 at 18:35

1

Daniel: This is not a rant. I learned haskell from RWH and they wrote about exceptions. But I have never used it later, so I wonder if exceptions are actually something to use when programming Haskell. In my current opinion, it is not usable.
–
telephoneOct 9 '11 at 18:42

7

@Daniel Even if it is a rant, it's still an interest worth discussing on SO. IMO this question clearly adds value as opposed to those newbie questions aka Is there a function IO a -> a?
–
FUZxxlOct 9 '11 at 19:12

You could imagine similar combinators for using Either instead of Maybe to report failure. So since we have the ability to handle these things with pure functions, why bother with the impure exception model? Well, most Haskellers will tell you to stick with purity. But the dark truth is, it's just a pain to add that extra layer. You can no longer write

prop_recip x = x == (recip . recip) x

Because now the result of recip x is in a Maybe. There are useful things you can do with (a -> a) functions that you can no longer do. Now you have to think about composing Maybes. This, of course, is trivial if you are comfortable with monads:

But therein lies the rub. Newbies generally know next to nothing when it comes to monadic composition. The Haskell Committee, as many on the #haskell irc channel will quickly tell you*, has made some rather wonky decisions regarding language design in order to cater to newbies. We want to be able to say "you don't need to know monads in order to start making useful things in Haskell". And I generally agree with that sentiment.

tl;dr
A few quick answers to the question: What is an exception?

a dirty hack so we don't have to make our functions entirely safe

a "try/catch" control flow mechanism for the IO monad (IO is a sin bin, so why not throw try/catch in the list of sins as well?)

Using other exceptions than 'error' in the reciprocal function is what I consider bad usage of exceptions. The function should never be called with that value and the program should never try to catch exceptions from it, if so there is a logical flaw in our program. I prefer to kill the program in such cases with 'error', to detect the bug. If the bug is handled silently with exception handling, it might cause other bugs later.
–
telephoneOct 9 '11 at 22:01

Clarification: I agree that handling exceptions silently is rather atrocious. I was just saying that error is (essentially) nothing more than a macro for (throw . ErrorCall), therefore I disagree that using exceptions other than 'error' is bad. You can kill the program with any ol' exception as long as you don't catch it; ErrorCall is no different. The nice thing about ErrorCall (and its convenience function error), however, is that it makes it so you can simply write your error message in a String, rather than going to the trouble of making your own Exception type.
–
Dan BurtonOct 10 '11 at 21:20

+1 for "it is obviously proven true by absence of objection." Made me lol.
–
wsanvilleOct 28 '11 at 15:09

The "error" function is for when a function receives invalid input, or when something internal happens that is supposed to never happen (i.e., a bug). In short, calling "error" represents a bug - either in the caller or callee.

The "undefined" constant is more for values which aren't supposed to be used - generally because they're going to be replaced with something else, or because they're phantom values used to get a specific type. (It's actually implemented as a call to "error".)

So why do we have Control.Exception with all its fanciness then?

Basically, "because I/O operations can throw exceptions". You could be happily talking to an FTP server over a TCP socket, and suddenly the connection breaks. The result? Your program throws an exception. Or you could run out of RAM, or the disk might fill up, or whatever.

Notice that almost all of these things are not your fault. If you can anticipate a specific thing going wrong, you should use things like Maybe and Either to handle it in a pure way. (E.g., if you're going to invert a matrix, well, the matrix could be non-invertible, so you'd better return a Maybe Matrix as the result.) For things that you can't reasonably anticipate (e.g., some other program just deleted the file you're trying to work on), exceptions are the way.

Note that Control.Exception contains lots of stuff for handling exceptions as well as just defining lots of different types. I don't care if the code I called did something which is incorrect and therefore a bug; I'd still like to be able to tell the client I was just talking to that the connection is about to be closed, log a description to a log file somewhere, and do other cleanup stuff, rather than just have my program suddenly, you know, stop.

Exceptions are a legitimate form of flow control. It's not clear to me why, when given a tool, programmers insist that it is "only for" certain cases and rule out other possible uses.

For example, if you are performing a backtracking computation, you can use exceptions to backtrack. In Haskell it would probably be more common to use the list monad for this, but exceptions are a legitimate way to go.