Haskell 不明确的类型变量‘;a0和x2019;因使用‘;例如,渔获物&x2019;

Haskell 不明确的类型变量‘;a0和x2019;因使用‘;例如,渔获物&x2019;,haskell,exception-handling,Haskell,Exception Handling,我一直在摆弄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(sh

我一直在摆弄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

我看到这一点就想,
a
的类型必须是
()
(单位类型)。我误解了什么,我应该如何结束我的示例,以便它捕获异常并显示错误?

GHC不知道为什么要捕获这种类型的异常

例如,此版本的outNum将捕获任何IOException:

outNum :: Int -> IO()
outNum i = Ex.catch (putStrLn(show (getNum i)))
           (\err -> putStrLn (show (err :: Ex.IOException)))
您可以使用
Ex.SomeException
捕获所有异常。但是,请参见 关于在美国这样做的评论

要捕获几种不同类型的异常,请参见

更新

指示您感兴趣的异常类型的另一种方法 是将处理程序定义为命名函数并提供“正常” 类型签名:

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

啊,我明白了。实际上,我没有意识到我可以添加这样的类型约束,这在使用lambdas时非常有用。这个特定的语法结构有名字吗?我把它叫做类型注释,你可以注释任何子表达式。我已经用一些额外的方式更新了答案,在catch call中向GHC提供了类型信息。谢谢Erik,我真的很感谢添加的细节,你帮了我很大的忙。
{-# LANGUAGE ScopedTypeVariables #-}

outNum i = putStrLn ...
             `catch` (\(err :: Ex.SomeException) -> putStrLn ("caught: " ++ show err))