3

在下面的:

import Data.Bifunctor
import qualified Data.ByteString.Lazy.UTF8 as BLU

safeReadFile :: FilePath -> ExceptT Text IO Text
safeReadFile p = (lift $ doesFileExist p) >>= bool (throwError "File does not exist") (lift $ pack <$> readFile p)

safeDecodeJSONFile :: FromJSON a => Text -> FilePath -> ExceptT Text IO a
safeDecodeJSONFile t f = do
  contents <- safeReadFile f
  tryRight $ first (\x -> pack (x ++ (unpack t))) (eitherDecode (BLU.fromString (unpack contents)))

当我运行时,runExceptT $ safeDecodeJSONFile "something" "nonExistantFile.json"我希望得到Left "Does not exist something",但我只是得到Left "Does not exist"- 我知道我传递给的函数first正在执行,因为没有packGHC 抱怨类型(eitherDecode (BLU.fromString (unpack contents)))ExceptT String IO a而不是ExceptT Text IO a- 那么为什么连接++也不会发生呢?

4

1 回答 1

2

你写过

safeDecodeJSONFile t f = do
  contents <- safeReadFile f
  tryRight $ ...

Monad实例ExceptT一击中就放弃Left,完全返回。所以tryRight ...永远不会发生。您需要Left明确地处理这个案例,也许使用catchError.

当我们这样做时,仍然有一个问题。你写

safeReadFile :: FilePath -> ExceptT Text IO Text
safeReadFile p = (lift $ doesFileExist p) >>= bool (throwError "File does not exist") (lift $ pack <$> readFile p)

不幸的是,这并不可靠。首先,文件不存在只是读取失败的一个原因——可能是权限错误、网络文件系统的网络问题、如果文件不是常规文件则出现设备错误等。其次,其他人可以删除在您检查它的存在和您尝试读取它的时间之间的文件。尝试处理文件时通常的建议是不要先检查。catch只需阅读文件并使用或类似的Control.Exception或围绕它们的包装器捕获任何异常

于 2019-08-02T16:49:19.147 回答