2012-01-13 46 views
2

拋出異常試圖拋出一個異常哈斯克爾:在Haskell和-XDeriveDataTypeable

import Control.Exception 
import Data.Typeable 

data MyException = ThisException | ThatException deriving (Show, Typeable) 
instance Exception MyException 

data CellPos = CellPos Int Int deriving (Show, Read) 

test :: String -> IO CellPos 
test str = do 
{ 
if length str == 0 
then 
    throw ThisException; 
else 
    return (CellPos 0 0); 
} 

編譯器說:

Can't make a derived instance of `Typeable MyException': 
    You need -XDeriveDataTypeable to derive an instance for this class 
In the data type declaration for `MyException' 

我怎樣才能解決這個問題?

你還可以寫我如何在調用測試函數時捕獲這樣的異常嗎?

回答

12

你會得到這個錯誤,因爲你試圖爲你的數據類型派生一個Typeable類的實例(deriving (Show, Typeable);異常類型需要一個Typeable實例),但這在標準中是不可能的哈斯克爾;你需要一個GHC擴展來完成它。

您可以手動編寫一個Typeable實例,但使用DeriveDataTypeable實際上是實現此目的的推薦方法。要啓用擴展程序,您可以將:

{-# LANGUAGE DeriveDataTypeable #-} 

位於源文件的頂部。在命令行上傳遞-XDeriveDataTypeable也可以,但不推薦使用;最好在文件頂部記錄您使用的語言擴展名,並且它還簡化了編譯,因爲您不必記住標誌。 (它還隔離擴展到需要它們的文件。)

此外,你應該在test定義與throwIO取代throw,因爲它guarantees the correct ordering在IO單子。

您還應該添加

import Prelude hiding (catch) 

的進口上面,作爲前奏的catch是一個較舊的異常處理機制,否則將Control.Exception衝突,當您嘗試和捕捉異常。

捕捉異常很簡單;你只需要使用catch

example :: IO() 
example = do 
    result <- test "hello" `catch` handler 
    ... 
    where handler ThisException = putStrLn "Oh no!" >> exitFailure 
     handler ThatException = putStrLn "Yikes!" >> exitFailure 

(該foo `catch` bar語法是一樣的catch foo bar;它可以用於任何功能。)

請注意,您的異常處理程序具有相同的返回類型的操作你」重新運行;你可以return一個合適的CellPos,通過傳遞給throwIO或通過其他方式從程序中退出,使異常冒泡到下一個處理程序(可能是全局異常處理程序,它只是打印異常並停止程序),如在本例中爲System.Exit.exitFailure

+0

謝謝你的男人!你還可以寫我如何在調用測試函數時捕獲這樣的異常? – user606521 2012-01-13 17:00:24

+0

@ user606521:好的;我用一個例子更新了我的答案。 – ehird 2012-01-13 17:07:12

4

要麼通過在-XDeriveDataTypeable在命令行,或放線

{-# LANGUAGE DeriveDataTypeable #-} 

在該文件的頂部。這兩種方法都指定了GHC需要派生Data和Typeable實例的語言擴展。我更喜歡第二種方法,因爲它將擴展的範圍限制爲需要它的文件。