これは、機能しているスコープ付き型変数GHC拡張機能です。詳細については、リンクをたどってください。
基本的に、一致する前にパターンが満たす必要のあるタイプに関するアサーションを定義します。だから、ええ、それは警備員に似ていますが、完全にそうではありません。
この特定の例はどのように機能しますか?「ベース」ライブラリのソースを調べて、次のことを確認してください。
class (Show e) => Exception e where
toException :: e -> SomeException
fromException :: SomeException -> Maybe e
data SomeException = forall e . Exception e => SomeException e
instance Exception IOException where
toException = IOException
fromException (IOException e) = Just e
fromException _ = Nothing
instance Exception ArithException where
toException = ArithException
fromException (ArithException e) = Just e
fromException _ = Nothing
これは、型クラスを実装するさまざまな型IOExceptionであることがわかります。また、これは、タイプの値をタイプ、などの値との間で変換できるラッピング/アンラッピングメカニズムであることがわかります。ArithExceptionExceptiontoException/fromExceptionExceptionIOExceptionArithException
したがって、次のように書くことができます。
f = expr `catches` [Handler handleArith,
Handler handleIO]
handleArith :: ArithException -> IO ()
handleArith ex = ....
handleIO :: IOException -> IO ()
handleIO ex = ....
それIOExceptionが起こったとしましょう。catchesHandlerハンドラーリストの最初の要素を処理するとき、それはを呼び出しtryHandler、それはを呼び出しますfromException。その定義から、のtryHandler戻り型はのfromException引数と同じである必要がありhandleArithます。一方、eタイプはException、つまり-(IOException ...)です。したがって、タイプはこのように再生されます(これは有効なハスケルではありませんが、私の主張を理解していただければ幸いです):
fromException :: (IOException ...) -> Maybe ArithException
そのinstance Exception IOException ...結果、結果はすぐに続くNothingので、このハンドラーはスキップされます。同じ理由で、次のハンドラーが呼び出されます。これは、fromExceptionを返すため(Just (IOException ...))です。
handleArithそのため、との型アノテーションを使用handleIOして、それぞれがいつ呼び出されるかを指定しfromException/toException、それがこのように行われることを確認しました。
必要に応じて、スコープ付き型変数を使用して、の定義内の型handleIOを制約することもできます。間違いなく、これにより読みやすさが向上する可能性があります。handleArithf
ファイナライズ、スコープ付き型変数はここでは主要なプレーヤーではありません。それらは単に便宜のために使用されます。この種のトリックをプレイするための主な機械はfromException/toException、友達です。スコープ付き型変数を使用すると、ガードパターンにより近い構文を使用できます。