以下:
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
的函数正在执行,因为没有pack
GHC抱怨(eitherDecode (BLU.fromString (unpack contents)))
的类型是ExceptT String IO a
而不是ExceptT Text IO a
-那么为什么也没有发生来自++
的串联?
答案 0 :(得分:1)
你写了
safeDecodeJSONFile t f = do
contents <- safeReadFile f
tryRight $ ...
Monad
的{{1}}实例在击中ExceptT
时立即放弃,并完全返回。因此Left
永远不会发生。您需要显式处理tryRight ...
情况,也许使用Left
。
虽然我们在做,但是仍然有问题。你写
catchError
不幸的是,这是不可靠的。首先,不存在的文件只是读取文件失败的原因-可能有权限错误,网络文件系统的网络问题,如果文件不是常规文件则设备错误等。其次,在您检查文件存在与尝试读取文件之间,其他人可能会删除文件。尝试处理文件时,通常的建议是 not 首先检查。只需读取文件并使用safeReadFile :: FilePath -> ExceptT Text IO Text
safeReadFile p = (lift $ doesFileExist p) >>= bool (throwError "File does not exist") (lift $ pack <$> readFile p)
中的catch
或类似内容或它们周围的包装器