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.
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.
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.
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.
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!"
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With