16

私はどこにでもこの回答を見つけることができなかったのに驚いています。エラー関数の呼び出しを捕捉(無視)する方法は?

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

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

これを回避するために、cやpythonのような他の言語では、エラーを無視したり、例外を無視したりすることが強制されますが、私の人生にとっては、それをどうやってhaskellで行うのか分かりません。エラー機能は回復できませんか?

ライブラリをローカルに変更して、その機能のエラーをチェックしないようにしますが、それは嫌です。私はカーソルを動かさずに最後の文字を描くことができる任意の回避策にもオープンしていますが、それは可能だとは思いません。

+0

"catch" [1]のHoogle。 2番目のリンクダウン。 [1] http://haskell.org/hoogle/?hoogle=catch –

+0

残念ながら問題のエラーはIOモナドにありません。まあ、それはIOで始まり、次にCursesモナドであるrunCurses、次にupdateMindであるupdateWindowに行きます。したがって、私はポールの答えがうまくいくとは思わない。しかし、ルキーは潜在的可能性があるように見えます。私が家に帰ると、私はそれを試していきます。 –

+0

ncursesを見ている私はそれがうまくいかないと感じています。 'drawText'は' error'を呼び出さず、C関数に直接委譲します。そして、それは 'ReaderT Window IO a' =' Window - > IO a'である 'Update'モナドで返されるので、' unsafeCleanup'はその*関数*を生成するときにエラーが発生したときにのみ動作します。アクションを実行している(ありそうもない)。あなたの選択肢は、IOのエラーをトップレベルでキャッチするか、cursesソースを開いて、よりローカルな 'catch'関数を注入させることです。 (これは簡単に行うことができ、カプセル化を破るだけです) – luqui

答えて

12

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) 

その後Maybeにそれを回すためにエラーに評価する任意の値の周りunsafeCleanupを包みます。

+0

btw、 'Exc。catch(Exc.evaluate(Just $!x))handler'は少しきれいになりますimho – hvr

+1

FWIWこれは[spoon](http://hackage.haskell.org/package/spoon)ライブラリに実装されました。 – luqui

+0

スプーンでは、「a - >たぶんa'の代わりに 'a - >どちらかの文字列a'を実行して、キャッチされたエラーのメッセージを見ることができますか?それとも禁忌であろうか? –

15

catchから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!" 
+0

putStrLnの '$' charはxDを削除できると思います。しかし、これは受け入れられた答えであるべきです。より洗練されたものです。 – dani24

関連する問題