编译器错误 – “句柄”函数和Real World Haskell

我正在阅读RWH,我来到第9章.它介绍了以下代码:

import System.IO
import Control.Exception

saferFileSize :: FilePath -> IO (Maybe Integer)
saferFileSize path = handle (\_ -> return Nothing) $do
  h <- openFile path ReadMode
  size <- hFileSize h
  hClose h
  return (Just size)

然而,它不会编译,给出以下错误消息:

test.hs:5:22:
    Ambiguous type variable `e0' in the constraint:
      (Exception e0) arising from a use of `handle'
    Probable fix: add a type signature that fixes these type variable(s)
    In the expression: handle (\ _ -> return Nothing)
    In the expression:
      handle (\ _ -> return Nothing)
      $do { h <- openFile path ReadMode;
             size <- hFileSize h;
             hClose h;
             return (Just size) }
    In an equation for `saferFileSize':
        saferFileSize path
          = handle (\ _ -> return Nothing)
            $do { h <- openFile path ReadMode;
                   size <- hFileSize h;
                   hClose h;
                   .... }

这里出了什么问题?为什么不编译?

在RWH出来之后不久之后,异常接口被更改为支持更灵活的处理程序,其中处理程序的类型确定将捕获哪些异常.例如.使用SomeException的处理程序将捕获任何东西(通常不是一个好主意),而使用IOException的处理程序将仅捕获IO异常.

因此,由于编译器无法推断您正在尝试捕获什么类型的异常,所以很容易遇到像“示例”中的“无事”处理程序的歧义问题.一个简单的方法来解决这个问题是为你的处理函数提供一个类型签名.

handle ((\_ -> return Nothing) :: IOException -> IO (Maybe Integer)) $do ...

虽然这可能有点冗长.另一种解决方案是专门处理.

handleIO :: (IOException -> IO a) -> IO a -> IO a
handleIO = handle

然后,只要您想处理IO异常,就可以使用handleIO,而无需拼写处理程序的类型签名.

saferFileSize path = handleIO (\_ -> return Nothing) $do ...

第三个选项是使用ScopedTypeVariables扩展,其中(除其他外)允许您仅为函数的参数提供类型注释,允许推断其余部分.

{-# LANGUAGE ScopedTypeVariables #-}
saferFileSize path = handle (\(_ :: IOException) -> return Nothing) $do ...
相关文章
相关标签/搜索