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 a
where 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
:Run Code Online (Sandbox Code Playgroud)catch f (\e -> ... (e :: SomeException) ...)
但是,这通常不是你想要做的!
例如,假设您要读取文件,但如果它不存在则继续,就像它包含一样
""
.您可能想要捕获所有异常并""
在处理程序中返回.然而,这会产生各种不良后果.例如,如果用户在恰当的时刻按下control-C,UserInterrupt
则会捕获异常,并且程序将在文件包含的信念下继续运行""
.同样,如果另一个线程试图杀死读取该文件的线程,则该ThreadKilled
异常将被忽略.相反,您应该只捕获您真正想要的异常.在这种情况下,这可能比"任何IO异常"更具体; 权限错误可能也希望以不同方式处理.相反,你可能想要这样的东西:
Run Code Online (Sandbox Code Playgroud)e <- tryJust (guard . isDoesNotExistError) (readFile f) let str = either (const "") id e
当你确实需要捕获任何异常时,有一些情况.但是,在大多数情况下,这只是为了你可以做一些清理; 你实际上对异常本身并不感兴趣.例如,如果您打开一个文件然后再想要关闭它,无论是处理文件还是正常执行还是抛出异常.然而,在这些情况下,您可以用这样的功能
bracket
,finally
并且onException
,它从来没有真正与你擦肩而过的异常,但只要调用清理功能,在适当的点.但有时你确实需要捕获任何异常,并实际看到异常是什么.一个例子是在程序的最顶层,您可能希望捕获任何异常,将其打印到日志文件或屏幕,然后优雅地退出.对于这些情况,您可以使用
catch
该SomeException
类型(或其他异常捕获函数之一).
资料来源: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)
顺便提一下,handle
GHC库文档中的示例使用不在6.10下编译.我已经提交了一份错误报告.