【问题标题】:Pure error handling in Haskell with Either: how to fold with error possibility?Haskell 中的纯错误处理与 Either:如何折叠错误可能性?
【发布时间】:2014-07-22 00:05:15
【问题描述】:

我主要对Either monad 和来自Control.Error 的所有uilitites 感兴趣。阅读errors-1.0: Simplified error handling,我确信纯错误应该与IO错误分开。这意味着errorfailexitFailure 是应简化为 IO monad 的函数。纯计算可以产生条件错误,但确定性

目前,在使用 folds 时,我遇到了一种情况,数组中的元素可能会产生条件错误,从而导致整个计算无法满足。例如(使用Data.ConfigFile):

type CPError = (CPErrorData, String)
data CPErrorData = ParseError String | ...
type SectionSpec = String
type OptionSpec = String

instance Error CPError
instance Error e => MonadError e (Either e)

get :: MonadError CPError m => ConfigParser -> SectionSpec -> OptionSpec -> m a


dereference :: ConfigParser -> String -> Either CPError String
dereference cp v = foldr replacer v ["executable", "args", "title"]
 where
  replacer :: String -> Either CPError String -> Either CPError String
  replacer string acc = do
    res <- acc
    value <- get cp "DEFAULT" string
    return $ replace ("${" ++ string ++ "}") value res

情况是:我使用了一个复杂类型的 acc,只是因为如果没有找到单个元素进行替换,那么整个值是不可计算的。

我的问题是:这丑吗? 有更好的方法吗?由于一些 IO 检查,我在 acc 中有一些更糟糕的 EitherT CPError IO String 类型的实用程序。

【问题讨论】:

    标签: haskell exception-handling error-handling fold either


    【解决方案1】:

    我现在明白我正在寻找一种方法来折叠可组合操作的列表。遇到this问题,了解到Kleisli操作符:

    dereferenceValue :: ConfigParser -> String -> Either CPError String
    dereferenceValue cp v = do
      foldr (>=>) return (fmap replacer ["executable", "args", "title"]) v
     where
      replacer :: String -> String -> Either CPError String
      replacer string res = do
        value <- get cp "DEFAULT" string
        return $ replace ("${" ++ string ++ "}") value res
    

    可能,这看起来有点像我的问题,但感觉更干净。特别是因为replacer的签名。 它不接收 Monad 作为第二个参数,而变得对代码的其他部分更有用

    编辑

    更简单:

    dereferenceValue :: ConfigParser -> String -> Either CPError String
    dereferenceValue cp v = do
      foldM replacer v ["executable", "args", "title"]
     where
      replacer :: String -> String -> Either CPError String
      replacer res string = do
        value <- get cp "DEFAULT" string
        return $ replace ("${" ++ string ++ "}") value res
    

    结论:学会使用Hoogle

    【讨论】:

      【解决方案2】:

      正如您所发现的,foldM 在这里工作得非常好。你的replacer 函数

      replacer :: String -> String -> Either String String
      replacer res string = do
        value <- get cp "DEFAULT" string
        return $ replace ("${" ++ string ++ "}") value res
      

      可以使用Applicative进一步美化如下

      replacer :: String -> String -> Either String String
      replacer res string =
        replace ("${" ++ string ++ "}") <$> get cp "DEFAULT" string <*> pure res
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-12-28
        • 2015-01-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-14
        相关资源
        最近更新 更多