21

これに対する答えがどこにも見つからなかったのには驚きました。

私はローグライクを書いていて、hackageのncursesライブラリを使用しています。これは、ncursesライブラリのかなり良いラッパーです。ncursesにはこの癖があり、右下の文字を書き込もうとすると、カーソルを次の文字に移動しようとしますが、移動先がないため失敗します。無視できるエラー値を返します。

私の問題は、haskell ncursesライブラリライターがすべての呼び出しでエラーがないか忠実にチェックし、エラーがある場合はエラー「drawText:etcなど」を呼び出すことです。

cやpythonのような他の言語では、これを回避するために、エラーを無視するか、例外をキャッチして無視する必要がありますが、私の人生では、haskellでそれを行う方法を理解できません。エラー関数は回復不能ですか?

必要に応じてその関数のエラーをチェックしないようにライブラリをローカルで変更しますが、そうするのは嫌です。また、カーソルを動かさずに最後の文字を描画できる回避策もありますが、それは不可能だと思います。

4

2 に答える 2

20

catchfromを使用してこれを行うことができますControl.Exception。ただし、IOこれを行うにはモナドにいる必要があることに注意してください。

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無限ループと同じくらい観察可能であると思われます。error「魔法をIO知っていればできる」と言っているようなものです。しかし、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 に答える