haskell - 模棱两可的类型变量错误信息

标签 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> 

Apparently it works fine in ghci 6.8, I am using 6.10.1.

Edit: I have minimized the code. I expect that to have the same result in both 6.8 and 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

试图编译它:

[1 of 1] 编译 Main(/tmp/foo.hs,解释)

/tmp/foo.hs:12:10:
约束中的模糊类型变量“a”:
由在/tmp/foo.hs:12:10-12 使用 `arg' 引起的 `C a'
可能的修复:添加修复这些类型变量的类型签名
失败,加载模块:无。
Prelude Control.Exception>

最佳答案

Control.Exception.handle的类型是:

handle :: Exception e => (e -> IO a) -> IO a -> IO a

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

你的情况就是这样,e应该是 Control.Exception.ErrorCall自从 undefined使用 error抛出ErrorCall (Exception 的一个实例)。

处理 undefined 的使用你可以定义类似 handleError :
handleError :: (ErrorCall -> IO a) -> IO a -> IO a
handleError = handle

它本质上是一个别名 Control.Exception.handlee固定为 ErrorCall这是什么error抛出。

中运行时看起来像这样GHCi 7.4.1 :
ghci> handleError (\_ -> return "err") undefined
"err"

要处理所有异常,请使用 handleAll函数可以写成如下:
handleAll :: (SomeException -> IO a) -> IO a -> IO a
handleAll = handle
Control.Exception 的这段摘录很好地描述了捕获所有异常的后果。文档:

Catching all exceptions

It is possible to catch all exceptions, by using the type SomeException:

catch f (\e -> ... (e :: SomeException) ...)

HOWEVER, this is normally not what you want to do!

For example, suppose you want to read a file, but if it doesn't exist then continue as if it contained "". You might be tempted to just catch all exceptions and return "" in the handler. However, this has all sorts of undesirable consequences. For example, if the user presses control-C at just the right moment then the UserInterrupt exception will be caught, and the program will continue running under the belief that the file contains "". Similarly, if another thread tries to kill the thread reading the file then the ThreadKilled exception will be ignored.

Instead, you should only catch exactly the exceptions that you really want. In this case, this would likely be more specific than even "any IO exception"; a permissions error would likely also want to be handled differently. Instead, you would probably want something like:

 e <- tryJust (guard . isDoesNotExistError) (readFile f)
 let str = either (const "") id e

There are occassions when you really do need to catch any sort of exception. However, in most cases this is just so you can do some cleaning up; you aren't actually interested in the exception itself. For example, if you open a file then you want to close it again, whether processing the file executes normally or throws an exception. However, in these cases you can use functions like bracket, finally and onException, which never actually pass you the exception, but just call the cleanup functions at the appropriate points.

But sometimes you really do need to catch any exception, and actually see what the exception is. One example is at the very top-level of a program, you may wish to catch any exception, print it to a logfile or the screen, and then exit gracefully. For these cases, you can use catch (or one of the other exception-catching functions) with the SomeException type.



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

关于haskell - 模棱两可的类型变量错误信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/431527/

相关文章:

haskell - Haskell 是否进行从 double 到整数的默认转换?

Haskell 无法将预期类型 [char] 与实际类型 IO 匹配

haskell - 理解(,)<$>长度<*>头部的类型

haskell - 添加约束会导致其他约束超出范围吗?

haskell - 如何告诉 Haskell 不要从两个模块导入同一个实例?

haskell - 将列表理解转换为递归调用

overloading - 为什么这些表达有不同程度的歧义?

c# - 为什么以下代码片段会成为 C#2.0 类型推断的问题?

haskell - FromJSON 实例的单例、类型族和存在类型

haskell - 如何为 GADT 实现棱镜?