为什么Data.Bifunctor的“ first”不转换此值

时间:2019-08-02 11:28:51

标签: haskell bifunctor

以下:

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-那么为什么也没有发生来自++的串联?

1 个答案:

答案 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或类似内容或它们周围的包装器

捕获任何异常