Either 和内部 Maybe 错误处理

Either and inner Maybe error handling

有没有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

也许不是最简单的函数,而是使用 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实例,因此我们可以使用>>=。在那种情况下,我们保持 Left x 不变,Right x 通过函数传递。

我们使用 maybe :: a -> (b -> a) -> Maybe b -> a 作为函数。所以我们把Nothing映射到Left err,我们用Right作为一个函数来变换Just x,在Right x.

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

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

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

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

首先,您可以使用 sequenceEither a (Maybe b) 变成 Maybe (Either a b)。然后,您可以将 fromMaybe 连同类型 a 的值应用于结果,以获得 Either a b.

import Data.Maybe (fromMaybe)

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

我会使用 errors 套餐,它提供

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

可以与另一个 EitherMonad 实例组合:

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