Compiler errors ";“处理”;函数与真实世界Haskell

Compiler errors ";“处理”;函数与真实世界Haskell,compiler-errors,haskell,Compiler Errors,Haskell,我在读RWH,我已经读到了第九章。它介绍了以下代码: 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

我在读RWH,我已经读到了第九章。它介绍了以下代码:

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)
import System.IO
导入控制。异常
安全文件大小::文件路径->IO(可能是整数)
saferFileSize路径=句柄(\ \ \->不返回任何内容)$do
h不返回任何内容)

$do{hRWH相当旧。在GHC6.10左右的版本中,
handle
函数签名已更改

要使用旧版本,请导入
Control.OldException
而不是Control.Exception`。您将收到弃用警告,但程序将编译

或者,您可以使用新接口并为处理程序提供显式签名,如下所示:

((\ _ -> return Nothing) :: IOException -> IO (Maybe Integer))

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

Haskell网站上的
handle
函数的文档对此非常不清楚(至少对于入门级人员——需要文档的人!),感谢您非常清楚的解释,编译器只需要我们指定要处理的异常类型!
{-# LANGUAGE ScopedTypeVariables #-}
saferFileSize path = handle (\(_ :: IOException) -> return Nothing) $ do ...