【问题标题】:Ambiguous type variable ‘a0’ arising from a use of ‘Ex.catch’由于使用“Ex.catch”而产生的模棱两可的类型变量“a0”
【发布时间】:2016-08-26 11:50:17
【问题描述】:

我一直在摆弄 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.catch”而产生的模棱两可的类型变量“a0”可防止 约束“(Ex.Exception a0)”被解决。

查看所涉及函数的定义:

catch :: IO a -> (IOError -> IO a) -> IO a
putStrLn :: String -> IO ()
show :: Show a => a -> String
error :: [Char] -> a

我看着这个想,a 的类型一定是()(单位类型)。我误解了什么,应该如何修改我的示例以便它捕获异常并显示错误?

【问题讨论】:

    标签: haskell exception-handling


    【解决方案1】:

    GHC 不知道您为什么要捕获的异常类型。

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

    outNum :: Int -> IO()
    outNum i = Ex.catch (putStrLn(show (getNum i)))
               (\err -> putStrLn (show (err :: Ex.IOException)))
    

    您可以使用Ex.SomeException 捕获所有异常。然而,见 Control.Exception docs中关于这样做的评论

    要捕获几种不同类型的异常,请参阅catches function

    更新

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

    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 调用中向 GHC 提供类型信息。
    • 谢谢 Erik,我非常感谢添加的细节,你帮了大忙。
    猜你喜欢
    • 2016-11-26
    • 1970-01-01
    • 2012-12-18
    • 2012-10-18
    • 2010-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多