2010-02-16 111 views
6

如果你看一下例子爲catchesHaskell中可以定義一個自定義防護機制嗎?

f = expr `catches` [Handler (\ (ex :: ArithException) -> handleArith ex), 
        Handler (\ (ex :: IOException) -> handleIO ex)] 

它看起來像catches已經定義了一個自定義機制來匹配模式(兩個異常類型)。我誤解了,還是可以將它擴展爲允許定義一個函數,該函數可以採用匹配特定模式的lambda函數?

編輯:FYI以下是GHC的漁獲物來源。如果有人能夠闡明這種工作方式,那將會很棒。

catches :: IO a -> [Handler a] -> IO a 
catches io handlers = io `catch` catchesHandler handlers 

catchesHandler :: [Handler a] -> SomeException -> IO a 
catchesHandler handlers e = foldr tryHandler (throw e) handlers 
    where tryHandler (Handler handler) res 
       = case fromException e of 
       Just e' -> handler e' 
       Nothing -> res 

回答

5

這是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 

我們看到,IOExceptionArithException是不同的類型實施類型類Exception。我們也看到,toException/fromException是包裝/解包機制,允許一個Exception類型的值從類型IOExceptionArithException值轉換成/等

所以,我們也許能寫:

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 ...))

因此,您已使用handleArithhandleIO的類型簽名來指定它們每個將被調用的時間,並且fromException/toException確保它以這種方式發生。

如果你願意,你也可以約束類型的handleIOhandleArithf的定義裏面,使用範圍的類型變量。可以說,這可以給你更好的可讀性。

最終確定,範圍類型變量不是這裏的主要參與者。它們只是爲了方便使用。玩這種技巧的主要機器是fromException/toException和朋友。作用域類型變量只允許你使用更接近守護模式的語法。

+0

作用域類型變量是如何涉及的?我沒有看到這種機制在捕獲的來源中起作用。 – me2 2010-02-16 16:39:56

+0

已更新爲解釋fromException/toException欺騙 – ADEpt 2010-02-16 22:30:14

1
case() of 
()| foo expr1 -> handleFooCase 
    | bar expr2 -> handleBarCase 
    | otherwise -> blah 
相關問題