22

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

    Prelude> :m +Control.Exception
    Prelude Control.Exception> 句柄 (\_-> return "err") 未定义

    <交互式>:1:0:
        约束中的模糊类型变量“e”:
          `异常 e'
            由在 <interactive>:1:0-35 处使用 `handle' 引起
        可能的修复:添加修复这些类型变量的类型签名
    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] 编译 Main(/tmp/foo.hs,解释)

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

5 回答 5

13

的类型Control.Exception.handle是:

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

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

它只是发生在你的情况下,e应该是Control.Exception.ErrorCall因为undefined使用errorwhich throws ErrorCall(的实例Exception)。

要处理您的使用,undefined可以定义如下内容handleError

handleError :: (ErrorCall -> IO a) -> IO a -> IO a
handleError = handle

它本质上是一个别名Control.Exception.handlee固定 as ErrorCallwhich is what errorthrows。

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

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

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

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

于 2012-09-07T01:57:28.930 回答
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> 

好吧,也许我终于可以做到这一点了。我认为问题在于单态限制,而是您遇到了读取/显示问题的一个实例:您提供处理某种类型的异常,在新版本的 `handle 中,有不止一种类型异常,并且该异常的类型不会出现在您的结果中。所以编译器无法知道你试图处理哪种类型的异常。解决这个问题的一种方法是选择一个。这是一些有效的代码:

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

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

于 2009-01-10T19:06:07.637 回答
3

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

于 2009-05-24T10:48:52.493 回答
2

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

import Control.Exception
let f _ = putStrLn "error" :: SomeException -> IO () 
in handle f undefined 
于 2009-05-26T03:02:33.663 回答
1

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

文档 说:

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

于 2009-01-10T19:18:26.660 回答