Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Meaning of Haskell exceptions

Tags:

haskell

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.

like image 773
telephone Avatar asked Oct 09 '11 16:10

telephone


People also ask

Does Haskell have exceptions?

There are three different ways exceptions can be thrown in Haskell: Synchronously thrown: an exception is generated from IO code and thrown inside a single thread. Asynchronously thrown: an exception is thrown from one thread to another thread to cause it to terminate early.

What is an exception in java?

Definition: An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions. When an error occurs within a method, the method creates an object and hands it off to the runtime system.

What is exceptions in laravel?

By default, the Laravel exception handler will convert exceptions into an HTTP response for you. However, you are free to register a custom rendering closure for exceptions of a given type. You may accomplish this via the renderable method of your exception handler.


2 Answers

In my humble opinion, exceptions mean "you broke the contract of a function". I'm not talking about the type contract, I'm talking about the stuff you generally find in comments.

-- The reciprocal is not defined for the value 0 myRecip :: Fractional a => a -> a myRecip x | x == 0    = throw DivideByZero           | otherwise = 1 / x 

Of course you could always provide this functions the "safe" way:

safeRecip :: Fractional a => a -> Maybe a safeRecip x | x == 0    = Nothing             | otherwise = Just $ 1 / x 

Perhaps we should even abstract this pattern

restrictInput :: (a -> Bool) -> (a -> b) -> (a -> Maybe b) restrictInput pred f x = if pred x then Just (f x) else Nothing  safeRecip' = restrictInput (/= 0) myRecip 

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:

prop_recip 0 = (safeRecip >=> safeRecip) 0 == Nothing prop_recip x = (safeRecip >=> safeRecip) x == Just x 

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?)

There may be other explanations.

See also Haskell Report > Basic Input/Output > Exception Handling in the IO Monad

*I actually asked on #haskell irc if they approved of this statement. The only response I got was "wonky" :) so it is obviously proven true by absence of objection.


[Edit] Note that error and undefined are defined in terms of throw:

error :: [Char] -> a error s = throw (ErrorCall s)  undefined :: a undefined =  error "Prelude.undefined" 
like image 154
Dan Burton Avatar answered Oct 14 '22 07:10

Dan Burton


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.

like image 30
MathematicalOrchid Avatar answered Oct 14 '22 06:10

MathematicalOrchid