我一直在摆弄Haskell,试图理解错误处理。在这样做的同时,我正试图掌握如何阅读和理解GHC的输出,以便我可以更好地调试类型错误。
我写了下面的测试:
import System.Environment
import qualified Control.Exception as Ex
getNum :: Int -> Int
getNum i = (!!) [1,2,3,4] i
outNum :: Int -> IO()
outNum i = Ex.catch (putStrLn(show (getNum i))) (err -> putStrLn (show err))
main = do
args <- getArgs
outNum 3
这会引发以下错误:
由于使用' Ex '而引起的歧义类型变量' a0 '。抓住"阻止约束条件(例2)异常a0) '无法解决。
查看所涉及的函数的定义:
catch :: IO a -> (IOError -> IO a) -> IO a
putStrLn :: String -> IO ()
show :: Show a => a -> String
error :: [Char] -> a
我看着这个并思考,a
的类型必须是()
(单位类型)。我误解了什么,我应该如何修改我的例子,以便它捕获异常并显示错误?
GHC不知道为什么要捕获异常类型。
例如,这个版本的outNum将捕获任何IOException:
outNum :: Int -> IO()
outNum i = Ex.catch (putStrLn(show (getNum i)))
(err -> putStrLn (show (err :: Ex.IOException)))
您可以使用Ex.SomeException
捕获所有异常。然而,看到关于在控制中这样做的评论。除了文档
要捕获几种不同类型的异常,请参阅catches
函数
指示您感兴趣的异常类型的另一种方法是将处理程序定义为一个命名函数,并提供一个"normal"类型签名:
outNum i = Ex.catch (putStrLn (show (getNum i))
handler
where handler :: Ex.IOException -> IO ()
handler err = putStrLn $ "caught: " ++ show err
,通常你会看到catch
写成中缀运算符:
outNum i = putStrLn (show (getNum i)) `catch` handler
最后,使用ScopedTypeVariables,您可以放置类型注释关于lambda的参数:
{-# LANGUAGE ScopedTypeVariables #-}
outNum i = putStrLn ...
`catch` ((err :: Ex.SomeException) -> putStrLn ("caught: " ++ show err))