【问题标题】:Either and inner Maybe error handlingEither 和 inner Maybe 错误处理
【发布时间】:2018-01-30 21:14:39
【问题描述】:

是否存在避免编写此自定义函数的 Haskell 模式?将 Maybe 中的 Nothing 作为错误处理的想法(作为包装 Either 的一部分):

eitherMaybeHandle :: String -> Either String (Maybe a) -> Either String a
eitherMaybeHandle err = \case
  Left e ->
    Left e
  Right Nothing ->
    Left err
  Right (Just a) ->
    Right a

【问题讨论】:

    标签: haskell error-handling maybe either


    【解决方案1】:

    首先,您可以使用sequenceEither a (Maybe b) 转换为Maybe (Either a b)。然后您可以将fromMaybea 类型的值一起应用于结果,以获得Either a b

    import Data.Maybe (fromMaybe)
    
    eitherMaybeHandle :: a -> Either a (Maybe b) -> Either a b
    eitherMaybeHandle err = fromMaybe (Left err) . sequence
    

    【讨论】:

    • 为什么将Either a (Maybe b)(它讲述了一个故事:你肯定会得到一个a,但如果有b,它会是首选)转换为相当的有意义令人困惑的Maybe (Either a b),讲述了完全不同的故事:你可能会得到一些东西,也可能得不到。我是 Haskell 的新手,但不是 FP 的新手。所以只是好奇为什么你认为这是一个很好的解决方案? (无论如何,+1)。
    • @SerejaBobolubov 我认为它是一个很好的解决方案,因为如果您熟悉这些功能,它会很短且相对易读。这里的其他答案也很容易阅读。就他们的故事而言,Either a (Maybe b)Maybe (Either a b) 是同构的(意味着它们包含相同数量的数据),但Maybe 具有更多的内置函数。
    • 不,他们不是。拥有Maybe 可能实际上意味着您一无所有。这样你就不能回到a,这是由Either a (Maybe b)保证的。
    • @SerejaBobolubov 使用Either a (Maybe b),使用Right Nothing 也可以一无所有。由于每个可能的值之间存在一对一的映射,因此它们是同构的。
    • 一对一是单射映射。您还需要满射来获得双射(即“同构”)。
    【解决方案2】:

    原始代码已经可以了。您可能需要考虑通过将每个分支保持在同一行上来减少占用的行数。

    否则,为了替代方案,您可以使用:

    eitherMaybeHandle :: String -> Either String (Maybe a) -> Either String a
    eitherMaybeHandle _   (Left e)         = Left e
    eitherMaybeHandle err (Right Nothing)  = Left err
    eitherMaybeHandle _   (Right (Just a)) = Right a
    

    甚至

    eitherMaybeHandle :: String -> Either String (Maybe a) -> Either String a
    eitherMaybeHandle _   (Left e)  = Left e
    eitherMaybeHandle err (Right x) = maybe (Left err) Right x
    

    我认为原始代码比后一种代码更具可读性。

    【讨论】:

      【解决方案3】:

      也许不是最简单的函数,而是尝试使用 monads 和 Maybe catamorphism,例如:

      import Data.Maybe(maybe)
      
      eitherMaybeHandle :: a -> Either a (Maybe b) -> Either a b
      eitherMaybeHandle err = (>>= maybe (Left err) Right)
      

      我们甚至可以去掉err参数,写成这样:

      eitherMaybeHandle :: a -> Either a (Maybe b) -> Either a b
      eitherMaybeHandle = (=<<) . flip maybe Right . Left
      

      由于Either a 是一个monad 实例,因此我们可以使用&gt;&gt;=。在这种情况下,我们保持 Left x 不变,而 Right x 通过函数传递。

      作为函数,我们使用maybe :: a -&gt; (b -&gt; a) -&gt; Maybe b -&gt; a。所以我们将Nothing 映射到Left err 上,并使用Right 作为函数将Just x 转换为Right x

      【讨论】:

        【解决方案4】:

        我会使用errors 包,它提供

        note :: a -> Maybe b -> Either a b
        

        它可以与另一个EitherMonad 实例结合使用:

        eitherMaybeHandle :: e -> Either e (Maybe a) -> Either e a
        eitherMaybeHandle err act = act >>= note err
        

        【讨论】:

        • 注意就像note x = maybe (Left x) Right一样简单
        • @phadej 绝对是。但通常当我发现自己需要将Maybe 提升为Either 时,我发现自己需要在附近的错误报告机制之间进行许多其他类型的转换,因此拖入整个包通常是值得的。
        猜你喜欢
        • 1970-01-01
        • 2015-12-28
        • 2015-01-26
        • 2021-01-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-23
        • 1970-01-01
        相关资源
        最近更新 更多