這是Scoped Type Variables GHC擴展工作。點擊鏈接瞭解更多信息。
基本上,你可以定義一個關於類型的斷言,它必須在模式匹配之前被模式匹配。所以,是的,這跟守衛很相似,但並不完全如此。
這個特殊的例子是如何工作的?潛入sources of "base" library找出:
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
和ArithException
是不同的類型實施類型類Exception
。我們也看到,toException/fromException
是包裝/解包機制,允許一個Exception
類型的值從類型IOException
,ArithException
值轉換成/等
所以,我們也許能寫:
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 ...)。因此,類型發揮出這種方式(這不是一個有效的Haskell,但我希望你明白我的意思):
fromException :: (IOException ...) -> Maybe ArithException
從立即的結果是Nothing
遵循instance Exception IOException ...
,所以這個處理程序被跳過。通過相同的推理,將會調用以下處理程序,因爲fromException
將返回(Just (IOException ...))
。
因此,您已使用handleArith
和handleIO
的類型簽名來指定它們每個將被調用的時間,並且fromException/toException
確保它以這種方式發生。
如果你願意,你也可以約束類型的handleIO
和handleArith
的f
的定義裏面,使用範圍的類型變量。可以說,這可以給你更好的可讀性。
最終確定,範圍類型變量不是這裏的主要參與者。它們只是爲了方便使用。玩這種技巧的主要機器是fromException/toException
和朋友。作用域類型變量只允許你使用更接近守護模式的語法。
作用域類型變量是如何涉及的?我沒有看到這種機制在捕獲的來源中起作用。 – me2 2010-02-16 16:39:56
已更新爲解釋fromException/toException欺騙 – ADEpt 2010-02-16 22:30:14