【问题标题】:Idiomatic way to write firstRightOrLefts in Haskell?在 Haskell 中写 firstRightOrLefts 的惯用方式?
【发布时间】:2014-11-05 19:57:28
【问题描述】:

我有以下方法:

firstRightOrLefts :: [Either b a] -> Either [b] a
firstRightOrLefts eithers = 
   case partitionEithers eithers of
      (_,  (x : _)) -> Right x
      (xs, _)       -> Left xs

困扰我的是丑陋的模式匹配,我想知道是否有更惯用的方法来编写这个方法。这个想法是我有一堆可以返回 Eithers 的计算,我只想得到第一个结果或所有错误消息。也许我使用了错误的数据结构。也许 Writer monad 更适合这项任务。在这一点上我真的不确定。为任何帮助干杯!

【问题讨论】:

    标签: haskell either


    【解决方案1】:

    相反的约定实际上只是 Either 的 monad 定义,sequence 的定义就足够了:

    ghci> :t sequence :: [Either a b] -> Either a [b]
    sequence :: [Either a b] -> Either a [b]
      :: [Either a b] -> Either a [b]
    

    因此,要将其实际应用于您的案例,我们需要一个函数 flipEither:

    firstRightOrLefts = fe . sequence . map fe
        where fe (Left a) = Right a
              fe (Right b) = Left b
    

    【讨论】:

    • 这实际上是一个绝妙的答案,它简单明了。让它再开放一天,以防万一有一个更简单的答案,否则我会接受这个作为答案。
    • 我的意思是,如果你愿意,你也可以写成firstRightOrLefts = go [] where go acc e = case e of [] -> Left (reverse acc); (Right r):es -> Right r; (Left l):es -> go (l:acc) es。我真正喜欢上述答案的地方在于,它表明您可能正在以与人们通常的做法相反的方式使用 Either monad(至少在此操作中):因为您想累积错误并在第一次成功时停止,与想要停止第一个错误的人相比,您的用例被翻转了。这可能无关紧要,但如果您正在编写解析器,了解这一点很有用!
    • 你也可以写fe = either Right Left
    【解决方案2】:

    ExceptMonadPlus 实例具有以下行为:

    import Control.Monad
    import Control.Monad.Trans.Except
    
    firstRightOrLefts :: [Either e a] -> Either [e] a
    firstRightOrLefts = runExcept . msum . fmap (withExcept (:[]) . except)
    

    【讨论】:

    • 这很好。特别是因为它使用标准运算符来完成工作。我将进一步关注这些类型,看看它是如何工作的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多