如何在Haskell中实现safeReadFile函数以产生Maybe String

Pao*_*tti 3 io monads haskell types exception-handling

我正在尝试loadFile在Haskell中实现一个安全功能,该功能可以捕获任何异常并产生a,Maybe String但以下实现无法编译

 import System.IO         (readFile)
 import Control.Exception (catch, IOException)

 -- readFile :: FilePath -> IO String

 -- this compiles good
 safeReadFile :: FilePath -> IO (Either IOException String)
 safeReadFile p =
    (Right <$> readFile p) `catch`
    (\e -> pure $ Left e)

 -- this does not!
 safeReadFile' :: FilePath -> IO (Maybe String)
 safeReadFile' p =
    (Just <$> readFile p) `catch` 
    (\e -> pure Nothing)
Run Code Online (Sandbox Code Playgroud)

有人可以解释为什么GCH提出以下问题吗?

  Ambiguous type variable ‘e0’ arising from a use of ‘catch’
  prevents the constraint ‘(GHC.Exception.Exception
                              e0)’ from being solved.
  Probable fix: use a type annotation to specify what ‘e0’ should be.
  These potential instances exist:
    instance GHC.Exception.Exception IOException
      -- Defined in ‘GHC.IO.Exception’
    ...plus 20 instances involving out-of-scope types
    (use -fprint-potential-instances to see them all)
Run Code Online (Sandbox Code Playgroud)

如何在e变量上应用必要的类型注释?Haskell文档没有任何提示:-(

chi*_*chi 5

您必须指定要捕获的异常类型。safeLoadFile明确提及IOException,而safeLoadFile'没有提及。

尝试以下方法:

safeLoadFile' :: FilePath -> IO (Maybe String)
safeLoadFile' p =
    (Just <$> loadFile p) `catch` 
    ((\e -> pure Nothing) :: IOException -> IO (Maybe String))
Run Code Online (Sandbox Code Playgroud)

或者找到一些类似的方法来注释变量的类型e。例如(\ (e :: IOException) -> ...),如果打开,也可以使用ScopedTypeVariables

另一个选择:

safeLoadFile' :: FilePath -> IO (Maybe String)
safeLoadFile' p = (Just <$> loadFile p) `catch` handler
   where
   handler :: IOException -> IO (Maybe String)
   handler _ = pure Nothing
Run Code Online (Sandbox Code Playgroud)