我正在尝试在Haskell中实现安全的loadFile
函数,该函数会捕获任何异常并产生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)
有人可以解释为什么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)
如何在e
变量上应用必要的类型注释? Haskell文档没有任何提示:-(
答案 0 :(得分:4)
您必须指定要捕获的异常类型。 safeLoadFile
明确提及IOException
,而safeLoadFile'
没有提及。
尝试以下方法:
safeLoadFile' :: FilePath -> IO (Maybe String)
safeLoadFile' p =
(Just <$> loadFile p) `catch`
((\e -> pure Nothing) :: IOException -> IO (Maybe String))
或者找到一些类似的方法来注释变量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