21

我很惊讶我在任何地方都找不到答案。

我正在写一个 roguelike,我正在使用来自 hackage 的 ncurses 库,它是 ncurses 库的一个非常好的包装器。现在 ncurses 有这个怪癖,如果你尝试写右下角的字符,它会这样做,然后它会尝试将光标移动到下一个字符,然后它会失败,因为无处可移动。它返回一个您只能忽略的错误值。

我的问题是haskell ncurses库编写者尽职尽责地检查所有调用中的任何错误,当有错误时,他调用:错误“drawText:etc etc.”。

在其他语言中,如 c 或 python,为了解决这个问题,你不得不忽略错误或捕获并忽略异常,但对于我来说,我无法弄清楚如何在 haskell 中做到这一点。误差函数不可恢复吗?

如果必须,我将在本地修改库以不检查该函数的错误,但我讨厌这样做。我也愿意接受任何允许我在不移动光标的情况下绘制最后一个字符的解决方法,但我认为这是不可能的。

4

2 回答 2

20

您可以使用catchfrom执行此操作Control.Exception。但是请注意,您需要在IOmonad 中才能执行此操作。

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!"
于 2010-11-22T07:55:35.293 回答
16

error应该像无限循环一样可观察。你只能赶上errorIO这就像说“是的,如果你会魔法,你就可以”。但是从 Haskell 真正好的部分,纯代码来看,它是不可恢复的,因此强烈建议不要在你的代码中使用,只要你曾经使用无限循环作为错误代码。

ncurses 是粗鲁的,让你变魔术来纠正它。我会说unsafePerformIO有必要清理它。除此之外,这与保罗的回答基本相同。

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)

然后环绕unsafeCleanup任何会评估为错误的值以将其转换为Maybe.

如果您不想自己编写它,可以在spoon包中使用它(而且您不应该——异常代码可能非常棘手,尤其是在存在线程的情况下)。

于 2010-11-22T18:06:55.973 回答