也许这就是你想要做的?我推了
try
进入可能抛出的特定调用,并利用
bimapEitherT
将异常转换为
Text
.
saveAuthKey :: ObjRef ProjectViewState -> Text -> ObjRef (Entity Server) -> IO (Either Text Text)
saveAuthKey _ path (entityVal . fromObjRef -> server) = runEitherT $ do
(targetFile, key) <- hoistEither $
(,) <$> note "Invalid target file name"
(T.stripPrefix "file://" path)
<*> note "No authentication key for that server!"
(serverAuthKey server)
bimapEitherT textEx (const mempty) . EitherT . try $
BS.writeFile (T.unpack targetFile) key
但是,我觉得这有点过分,因为可以抛出异常的部分被本地化为一个调用(
BS.writeFile
)而可以返回的部分
Left
都是事先发生的纯计算。
EitherT
当你有代码将
Either
和
IO
逻辑很重,但这里的分离非常清楚。以下是我在没有
EitherT公司
:
saveAuthKey :: ObjRef ProjectViewState -> Text -> ObjRef (Entity Server) -> IO (Either Text Text)
saveAuthKey _ path (entityVal . fromObjRef -> server) =
either (return . Left) save authKey
where authKey = (,) <$> note "Invalid target file name"
(T.stripPrefix "file://" path)
<*> note "No authentication key for that server!"
(serverAuthKey server)
save (targetFile, key) = either (Left . textEx) (const (Right ""))
<$> try (BS.writeFile (T.unpack targetFile) key)