首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用EitherT处理异常

用EitherT处理异常
EN

Stack Overflow用户
提问于 2015-01-22 18:26:17
回答 1查看 475关注 0票数 2

我已经问了一个类似的问题:例外和单台变压器,但不知何故,我没有正确地表达自己,并得到了另一个问题的答案,而不是我想问的那个问题(至少我是这么理解的)。

我现在又碰到了这个问题,让我再试一次来阐述我的问题.

我必须编写一个函数,其中包含一个可以保存身份验证密钥的服务器,以及一个保存身份验证密钥内容的目标文件。

代码语言:javascript
复制
saveAuthKey :: Text -> Server -> IO (Either Text Text)

函数可以在以下三种情况下返回Left

  1. 目标路径格式错误:不以"file://“”开头
  2. 服务器不持有身份验证密钥
  3. 保存文件的密钥时出现IO错误。

在我看来,这是EitherT的主要候选人。

所以我首先要说的是:

代码语言:javascript
复制
{-# LANGUAGE OverloadedStrings #-}

import Control.Error
import Control.Monad.Trans
import Data.Text (Text)
import qualified Data.Text as T
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Control.Exception

data Server = Server { authKey :: Maybe ByteString }

main = putStrLn "OK"

saveAuthKey :: Text -> Server -> IO (Either Text Text)
saveAuthKey path server = do
    result <- try $ runEitherT $ do
        targetFile <- hoistEither $ note "Invalid target file name"
            $ T.stripPrefix "file://" path
        key <- hoistEither $ note "No authentication key for that server!"
            $ authKey server
        lift $ BS.writeFile (T.unpack targetFile) key

我将try应用于runEitherT之上,因此try将结果封装在另一个Either中。不太优雅。但如果我不直接试一试,例外情况就不会被抓住。在我的前一个问题中,我试图将try放在lift旁边的runEitherT中,这也不能很好地工作。

所以,如果你必须用这个签名写一个这样的函数,你会如何处理呢?我也明白,我应该让一些例外通过而不是系统地捕捉SomeException,我不认为它与我的问题直接相关。假设使用try,我将捕获相关错误(磁盘已满,没有写权限等等)。

我根本无法执行try,并让调用方处理它(毕竟所有这些函数都在IO monad中,因此存在风险),但是在某些时候,必须有人使用try。在我的例子中,我使用的是hsqml库,这是haskell中处理的Javascript调用,如果我允许应用程序中的异常崩溃。

编辑:我给出了这个问题的当前解决方案,在这个承诺中。不过,我觉得可以在这个函数中实现更好的功能,而不必更改应用程序其余部分的设计。请注意,我捕获了所有的异常,我知道这是不建议的,但是暂时可以。没有比这更好的事情了吗?还是我把问题搞错了?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-01-23 00:45:41

也许这就是你想要做的?我将try推入可以抛出的特定调用中,并使用bimapEitherT将异常转换为Text

代码语言:javascript
复制
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的部分都是事先发生的纯计算。当您的代码在很大程度上交织了EitherIO逻辑时,Either是很好的,但是在这里,分离是非常清楚的。下面是我如何在没有EitherT的情况下编写它

代码语言:javascript
复制
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)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28096091

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档