模糊类型变量错误消息

时间:2009-01-10 18:49:45

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

尝试编译它:

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

5 个答案:

答案 0 :(得分:11)

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的{​​{1}}(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文档的摘录中详细描述:

  

捕获所有异常

     

使用类型SomeException

可以捕获所有异常
catch f (\e -> ... (e :: SomeException) ...)
     

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

     

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

     

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

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

有些时候你确实需要捕获任何异常。但是,在大多数情况下,这只是为了你可以做一些清理;你实际上对异常本身并不感兴趣。例如,如果您打开一个文件然后再想要关闭它,无论是处理文件还是正常执行还是抛出异常。但是,在这些情况下,您可以使用bracketfinallyonException之类的函数,它们实际上从未向您传递异常,只是在适当的位置调用清理函数。

     

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

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

答案 1 :(得分: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> 

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

Prelude Control.Exception> let alwaysError :: SomeException -> IO String; alwaysError = \_ -> return "err"
Prelude Control.Exception> handle alwaysError undefined
"err"

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

答案 2 :(得分:3)

解决方法是在ghc 6.10。*而不是Control.OldException中使用Control.Exception

答案 3 :(得分:2)

尝试为处理程序提供类型SomeException -> IO x,其中x是具体类型,例如

import Control.Exception
let f _ = putStrLn "error" :: SomeException -> IO () 
in handle f undefined 

答案 4 :(得分:1)

“异常e”可能来自“句柄”的类型签名。

The documentation 表示:

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

在GHC 6.8中它曾经不同,这可以解释为什么我没有得到这个错误。

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

似乎你遇到了单态限制。那个“_” - 模式必须是单态的(与ghc 6.8一样)或明确输入。 “解决方法”是将模式放在定义的左侧,它构成Haskell报告指定的“简单模式绑定”。

试试这个:

let f _ = return "err"
handle f undefined

http://www.haskell.org/haskellwiki/Monomorphism_restriction