在Haskell和-XDeriveDataTypeable中引发异常
正在尝试在Haskell中引发异常:在Haskell和-XDeriveDataTypeable中引发异常,haskell,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
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'
我怎么能修好它
你能不能也写下调用测试函数时如何捕获这种异常?在命令行中传入
-XDeriveDataTypeable
,或者将
{-# LANGUAGE DeriveDataTypeable #-}
在文件的顶部。这两种方法中的任何一种都指定GHC派生数据实例和可类型实例所需的语言扩展。我更喜欢第二种方法,因为它将扩展的范围限制在需要它的文件上。出现此错误是因为您试图为数据类型派生可类型类的实例(使用
派生(Show,Typeable)
;异常类型需要可类型实例),但这在标准哈斯克尔是不可能的;您需要一个GHC扩展来完成此操作
您可以手动编写一个可键入实例,但使用DeriveDataTypeable
实际上是推荐的方法。要启用扩展,您可以放置:
{-# LANGUAGE DeriveDataTypeable #-}
在源文件的顶部。在命令行上传递-XDeriveDataTypeable
也可以,但不建议这样做;最好在文件顶部记录您使用的语言扩展名,这也简化了编译,因为您不必记住标志。(它还隔离了需要它们的文件的扩展名。)
此外,在test
的定义中,应将throw
替换为throwIO
,就像在IO单子中一样
您还应该添加
import Prelude hiding (catch)
在您的导入之上,因为Prelude的catch
用于旧的异常处理机制,否则,当您尝试捕获异常时,该机制将与Control.exception冲突
捕获异常很简单;您只需使用:
示例::IO()
示例=do
结果>退出失败
处理程序ThatException=putStrLn“Yikes!”>>exitFailure
(foo`catch`bar
语法与catch foo bar
相同;它适用于任何函数。)
请注意,异常处理程序必须与正在运行的操作具有相同的返回类型;通过将异常传递给
throwIO
,您可以返回一个合适的CellPos
,使异常冒泡到下一个处理程序(可能是全局异常处理程序,它只是打印异常并停止程序),或者以其他方式从程序中退出,如本例所示。谢谢!你能不能也写下我在调用测试函数时如何捕捉这种异常?
example :: IO ()
example = do
result <- test "hello" `catch` handler
...
where handler ThisException = putStrLn "Oh no!" >> exitFailure
handler ThatException = putStrLn "Yikes!" >> exitFailure