在Haskell和-XDeriveDataTypeable中抛出异常

时间:2012-01-13 16:32:14

标签: haskell

尝试在Haskell中抛出异常:

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'

我该如何解决?

您是否还可以编写在调用测试函数时如何捕获此类异常?

2 个答案:

答案 0 :(得分:12)

您收到此错误是因为您尝试为您的数据类型派生Typeable类的实例(使用deriving (Show, Typeable);异常类型需要Typeable实例),但这不是可能在标准的Haskell中;你需要一个GHC扩展来做到这一点。

您可以手动编写Typeable实例,但实际上建议使用DeriveDataTypeable。要启用扩展程序,您可以输入:

{-# LANGUAGE DeriveDataTypeable #-}

位于源文件的顶部。在命令行上传递-XDeriveDataTypeable也可以,但不建议这样做;最好记录您在文件顶部使用的语言扩展,并且还简化了编译,因为您不必记住标志。 (它还将扩展名隔离到需要它们的文件。)

此外,您应该将throw替换为throwIO的定义test,因为它在IO monad中为guarantees the correct ordering

您还应该添加

import Prelude hiding (catch)

在你的导入之上,因为Prelude的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

答案 1 :(得分:4)

在命令行传递-XDeriveDataTypeable,或者放行

{-# LANGUAGE DeriveDataTypeable #-}

位于文件顶部。这些方法中的任何一个都指定GHC需要派生数据和可输入实例的语言扩展。我更喜欢第二种方法,因为它将扩展的范围限制在需要它的文件中。