Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to catch (and ignore) a call to the error function?

Tags:

I'm surprised I couldn't find an answer to this anywhere.

I'm writing a roguelike and I'm using the ncurses library from hackage, which is a pretty good wrapper around the ncurses library. Now ncurses has this quirk where if you try to write the bottom right character, it does so, then it tries to move the cursor to the next character, then it fails because there's nowhere to move it to. It returns an error value that you can only ignore.

My problem is that the haskell ncurses library writer dutifully checks for any errors on all calls, and when there is one, he calls: error "drawText: etc etc.".

In other languages, like c or python, to get around this you are forced to ignore the error or catch and ignore the exception, but for the life of me I can't figure out how to do it in haskell. Is the error function unrecoverable?

I will modify the library locally to not check for errors on that function if I have to, but I hate to do that. I'm also open to any workaround that would allow me to draw that last character without moving the cursor, but I don't think that is possible.

like image 907
David McHealy Avatar asked Nov 22 '10 07:11

David McHealy


People also ask

How do you throw and catch error?

Throw, and Try...Catch... The try statement defines a code block to run (to try). The catch statement defines a code block to handle any error. The finally statement defines a code block to run regardless of the result. The throw statement defines a custom error.

Can we use error in catch block?

You can use it in a catch clause, but you should never do it! If you use Throwable in a catch clause, it will not only catch all exceptions; it will also catch all errors. Errors are thrown by the JVM to indicate serious problems that are not intended to be handled by an application.

How do you handle errors in catch block?

You can put a try catch inside the catch block, or you can simply throw the exception again. Its better to have finally block with your try catch so that even if an exception occurs in the catch block, finally block code gets executed.


2 Answers

You can do this using catch from Control.Exception. Note, however, that you need to be in the IO monad to do this.

import qualified Control.Exception as Exc  divide :: Float -> Float -> Float divide x 0 = error "Division by 0." divide x y = x / y  main :: IO () main = Exc.catch (print $ divide 5 0) handler     where         handler :: Exc.ErrorCall -> IO ()         handler _ = putStrLn $ "You divided by 0!" 
like image 64
Paul Avatar answered Oct 20 '22 19:10

Paul


error is supposed to be as observable as an infinite loop. You can only catch error in IO, which is like saying "yeah you can if you know magic". But from the really nice part of Haskell, pure code, it is unrecoverable, and thus it is strongly advised not to use in your code, only as much as you would ever use an infinite loop as an error code.

ncurses is being rude and making you do magic to correct it. I'd say unsafePerformIO would be warranted to clean it up. Other than that, this is largely the same as Paul's answer.

import qualified Control.Exception as Exc  {-# NOINLINE unsafeCleanup #-} unsafeCleanup :: a -> Maybe a unsafeCleanup x = unsafePerformIO $ Exc.catch (x `seq` return (Just x)) handler     where     handler exc = return Nothing  `const`  (exc :: Exc.ErrorCall) 

Then wrap unsafeCleanup around any value that would evaluate to an error to turn it into a Maybe.

This is available in the spoon package if you don't want to write it yourself (and you shouldn't -- exception code can be really tricky, especially in the presence of threads).

like image 45
luqui Avatar answered Oct 20 '22 18:10

luqui