模糊类型变量错误消息

lun*_*ain 22 haskell type-inference typeclass

我不认为这是一个错误,但我有点困惑,为什么这不起作用.一个额外的问题是它为什么提到变量e?没有变量e.

    Prelude> :m +Control.Exception
    Prelude Control.Exception> handle (\_-> return "err") undefined

    <interactive>:1:0:
        Ambiguous type variable `e' in the constraint:
          `Exception e'
            arising from a use of `handle' at <interactive>:1:0-35
        Probable fix: add a type signature that fixes these type variable(s)
    Prelude Control.Exception> 

显然它在ghci 6.8中工作正常,我使用的是6.10.1.

编辑:我已经最小化了代码.我希望在6.8和6.10中都能得到相同的结果

class C a                                                                                                     

foo :: C a => (a -> Int)-> Int                                                                                
foo _ = 1                                                                                                     

arg :: C a => a -> Int                                                                                        
arg _ = 2                                                                                                     

bar :: Int                                                                                                    
bar = foo arg
Run Code Online (Sandbox Code Playgroud)

试图编译它:

[1 of 1] Compiling Main             ( /tmp/foo.hs, interpreted )

/tmp/foo.hs:12:10:
    Ambiguous type variable `a' in the constraint:
      `C a' arising from a use of `arg' at /tmp/foo.hs:12:10-12
    Probable fix: add a type signature that fixes these type variable(s)
Failed, modules loaded: none.
Prelude Control.Exception> 

Ala*_*Dea 12

类型Control.Exception.handle是:

handle :: Exception e => (e -> IO a) -> IO a -> IO a
Run Code Online (Sandbox Code Playgroud)

您看到的问题是lambda表达式(\_ -> return "err")的类型不是e -> IO awhere e的实例Exception.像泥一样清楚?好.现在我将提供一个实际上应该有用的解决方案:)

它恰好发生在你的情况下e应该是Control.Exception.ErrorCall因为undefined使用error了抛出ErrorCall(一个实例Exception).

要处理undefined你的用途,可以定义如下内容handleError:

handleError :: (ErrorCall -> IO a) -> IO a -> IO a
handleError = handle
Run Code Online (Sandbox Code Playgroud)

它本质上是一个固定的别名Control.Exception.handle,e因为ErrorCall它是error抛出的.

GHCi 7.4.1中运行时看起来像这样:

ghci> handleError (\_ -> return "err") undefined
"err"
Run Code Online (Sandbox Code Playgroud)

要处理所有异常,handleAll可以按如下方式编写函数:

handleAll :: (SomeException -> IO a) -> IO a -> IO a
handleAll = handle
Run Code Online (Sandbox Code Playgroud)

捕获所有异常后果在本Control.Exception文档的摘录中有很好的描述:

捕获所有异常

通过使用以下类型可以捕获所有异常SomeException:

catch f (\e -> ... (e :: SomeException) ...)
Run Code Online (Sandbox Code Playgroud)

但是,这通常不是你想要做的!

例如,假设您要读取文件,但如果它不存在则继续,就像它包含一样"".您可能想要捕获所有异常并""在处理程序中返回.然而,这会产生各种不良后果.例如,如果用户在恰当的时刻按下control-C,UserInterrupt则会捕获异常,并且程序将在文件包含的信念下继续运行"".同样,如果另一个线程试图杀死读取该文件的线程,则该ThreadKilled异常将被忽略.

相反,您应该只捕获您真正想要的异常.在这种情况下,这可能比"任何IO异常"更具体; 权限错误可能也希望以不同方式处理.相反,你可能想要这样的东西:

 e <- tryJust (guard . isDoesNotExistError) (readFile f)
 let str = either (const "") id e
Run Code Online (Sandbox Code Playgroud)

当你确实需要捕获任何异常时,有一些情况.但是,在大多数情况下,这只是为了你可以做一些清理; 你实际上对异常本身并不感兴趣.例如,如果您打开一个文件然后再想要关闭它,无论是处理文件还是正常执行还是抛出异常.然而,在这些情况下,您可以用这样的功能bracket,finally并且onException,它从来没有真正与你擦肩而过的异常,但只要调用清理功能,在适当的点.

但有时你确实需要捕获任何异常,并实际看到异常是什么.一个例子是在程序的最顶层,您可能希望捕获任何异常,将其打印到日志文件或屏幕,然后优雅地退出.对于这些情况,您可以使用catchSomeException类型(或其他异常捕获函数之一).

资料来源:http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception.html#g:4


Nor*_*sey 10

此问题仅出现在GHC 6.10中; 它不能在GHC 6.8中重复,因为它的类型handle不同:

: nr@homedog 620 ; ghci
GHCi, version 6.8.2: http://www.haskell.org/ghc/  :? for help
Loading package base ... linking ... done.
Prelude> :m +Control.Exception
Prelude Control.Exception>  handle (\_ -> return "err") undefined
"err"
Prelude Control.Exception> 
Run Code Online (Sandbox Code Playgroud)

好吧也许我终于可以做到这一点了.我认为问题不是单态限制,而是你遇到了一个Read/Show问题的实例:你提供处理某种类型的异常,在新版本的`handle中,有多种类型异常,并且该异常的类型不会出现在您的结果中.所以编译器有没有办法知道哪个你想处理的异常类型.一种方法是选择一种方法.这里有一些有用的代码:

Prelude Control.Exception> let alwaysError :: SomeException -> IO String; alwaysError = \_ -> return "err"
Prelude Control.Exception> handle alwaysError undefined
"err"
Run Code Online (Sandbox Code Playgroud)

顺便提一下,handleGHC库文档中的示例使用不在6.10下编译.我已经提交了一份错误报告.