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
我认为原始代码比后者更具可读性。
首先,您可以使用 sequence
将 Either 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
可以与另一个 Either
与 Monad
实例组合:
eitherMaybeHandle :: e -> Either e (Maybe a) -> Either e a
eitherMaybeHandle err act = act >>= note err
有没有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
我认为原始代码比后者更具可读性。
首先,您可以使用 sequence
将 Either 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
可以与另一个 Either
与 Monad
实例组合:
eitherMaybeHandle :: e -> Either e (Maybe a) -> Either e a
eitherMaybeHandle err act = act >>= note err