22

バグではないと思いますが、なぜうまくいかないのか少し不思議です。おまけの質問は、なぜ変数 e に言及しているのかということです。変数 e はありません。

    前奏曲> :m +Control.Exception
    プレリュード Control.Exception> handle (\_-> return "err") undefined

    <インタラクティブ>:1:0:
        制約内のあいまいな型変数「e」:
          「例外 e」
            <interactive>:1:0-35 での「ハンドル」の使用に起因する
        考えられる修正: これらの型変数を修正する型シグネチャを追加します。
    Prelude Control.Exception>

どうやら ghci 6.8 で問題なく動作するようです。私は 6.10.1 を使用しています。

編集:コードを最小化しました。6.8と6.10の両方で同じ結果になると思います

class C a                                                                                                     

foo :: C a => (a -> Int)-> Int                                                                                
foo _ = 1                                                                                                     

arg :: C a => a -> Int                                                                                        
arg _ = 2                                                                                                     

bar :: Int                                                                                                    
bar = foo arg

それをコンパイルしようとしています:

[1/1] Main のコンパイル ( /tmp/foo.hs、解釈済み )

/tmp/foo.hs:12:10:
    制約内のあいまいな型変数「a」:
      /tmp/foo.hs:12:10-12 での「arg」の使用による「C a」
    考えられる修正: これらの型変数を修正する型シグネチャを追加します。
失敗しました。モジュールがロードされました: なし。
Prelude Control.Exception>
4

5 に答える 5

13

のタイプControl.Exception.handleは次のとおりです。

handle :: Exception e => (e -> IO a) -> IO a -> IO a

あなたが見ている問題は、ラムダ式がのインスタンスである(\_ -> return "err")e -> IO aではないことです。泥のように透明?良い。ここで、実際に役立つはずのソリューションを提供します:)eException

あなたのケースでは、 which throws (のインスタンス)を使用しているため、そうなるeはずです。Control.Exception.ErrorCallundefinederrorErrorCallException

の使用を処理するには、次のundefinedようなものを定義できますhandleError

handleError :: (ErrorCall -> IO a) -> IO a -> IO a
handleError = handle

これは基本的に、何がスローされるかControl.Exception.handlee固定したエイリアスです。ErrorCallerror

GHCi 7.4.1で実行すると、次のようになります。

ghci> handleError (\_ -> return "err") undefined
"err"

すべての例外を処理するhandleAllには、次のように関数を記述できます。

handleAll :: (SomeException -> IO a) -> IO a -> IO a
handleAll = handle

Control.Exceptionすべての例外をキャッチすると、次のドキュメントの抜粋でよく説明されている結果が得られます。

すべての例外をキャッチする

type を使用して、すべての例外をキャッチすることができますSomeException

catch f (\e -> ... (e :: SomeException) ...)

ただし、これは通常、やりたいことではありません。

たとえば、ファイルを読み取りたいが、それが存在しない場合は、含まれているかのように続行するとし""ます。""すべての例外をキャッチしてハンドラーに戻りたいと思うかもしれません。ただし、これにはあらゆる種類の望ましくない結果があります。たとえば、ユーザーが適切なタイミングで control-C を押すと、UserInterrupt例外がキャッチされ、プログラムはファイルに含まれているという信念の下で実行を継続します""。同様に、別のスレッドがファイルを読み込んでいるスレッドを強制終了しようとすると、ThreadKilled例外は無視されます。

代わりに、本当に必要な例外だけをキャッチする必要があります。この場合、これは「任意の IO 例外」よりも具体的である可能性があります。アクセス許可エラーも別の方法で処理する必要があります。代わりに、おそらく次のようなものが必要になるでしょう。

 e <- tryJust (guard . isDoesNotExistError) (readFile f)
 let str = either (const "") id e

あらゆる種類の例外を本当にキャッチする必要がある場合があります。ただし、ほとんどの場合、これはクリーンアップを行うためのものです。実際には例外自体には興味がありません。たとえば、ファイルを開いている場合、ファイルの処理が正常に実行されるか、例外がスローされるかに関係なく、ファイルを再度閉じる必要があります。ただし、これらの場合、実際には例外を渡すことはなく、適切なポイントでクリーンアップ関数を呼び出すだけの 、bracketfinallyなどの関数を使用できます。onException

しかし、例外をキャッチし、実際に例外が何であるかを実際に確認する必要がある場合もあります。1 つの例は、プログラムの最上位レベルにあります。例外をキャッチし、それをログファイルまたは画面に出力してから、正常に終了することができます。catchこれらのケースでは、 (または他の例外をキャッチする関数の 1 つ) を型と共に使用できますSomeException

ソース: http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception.html#g:4

于 2012-09-07T01:57:28.930 に答える
10

この問題は GHC 6.10 でのみ発生します。handleの型が異なるため、GHC 6.8 では複製できません。

: nr@homedog 620 ; ghci
GHCi, version 6.8.2: http://www.haskell.org/ghc/  :? for help
Loading package base ... linking ... done.
Prelude> :m +Control.Exception
Prelude Control.Exception>  handle (\_ -> return "err") undefined
"err"
Prelude Control.Exception> 

よし、やっとこれを正しく理解できるかもしれない。問題はモノモーフィズムの制限ではなく、読み取り/表示の問題のインスタンスに遭遇したと思います: 何らかのタイプの例外を処理することを提案しています.`ハンドルの新しいバージョンでは、複数のタイプがあります.の例外であり、その例外のタイプは結果に表示されません。したがって、コンパイラは、処理しようとしている例外の種類を知る方法がありません。これを行う 1 つの方法は、1 つを選択することです。動作するコードは次のとおりです。

Prelude Control.Exception> let alwaysError :: SomeException -> IO String; alwaysError = \_ -> return "err"
Prelude Control.Exception> handle alwaysError undefined
"err"

ちなみに、handleGHC ライブラリのドキュメントにある の使用例は、6.10 ではコンパイルされません。バグレポートを提出しました。

于 2009-01-10T19:06:07.637 に答える
3

回避策は、Control.OldExceptionの代わりに ghc 6.10.* で使用することですControl.Exception

于 2009-05-24T10:48:52.493 に答える
2

ハンドラーに type を指定してみてくださいSomeException -> IO x。x は具象型です。

import Control.Exception
let f _ = putStrLn "error" :: SomeException -> IO () 
in handle f undefined 
于 2009-05-26T03:02:33.663 に答える
1

「例外 e」は、「handle」の型シグネチャからの可能性があります。

ドキュメント には次のように記載されています。

handle :: Exception e => (e -> IO a) -> IO a -> IO a

GHC 6.8 では以前は違っていたので、そのエラーが発生しない理由が説明できます。

handle :: (Exception -> IO a) -> IO a -> IO a

モノモーフィズムの制限に直面しているようです。その "_"-Pattern はモノモーフィック (ghc 6.8 の場合) であるか、明示的に型指定されている必要があります。「回避策」は、定義の左側にパターンを配置することです。これは、Haskell レポートで指定されている「単純なパターン バインディング」を構成します。

これを試して:

let f _ = return "err"
handle f undefined

http://www.haskell.org/haskellwiki/Monomorphism_restriction

于 2009-01-10T19:18:26.660 に答える