有几种方法:
如果您想显式处理结果,可以在 Either 构造函数上进行模式匹配:
foo :: Either a b -> c
foo (Left a) = <some function from (a -> c)>
foo (Right b) = <some function from (b -> c)>
如果您有一些要根据先前结果处理的条件,则可以使用 Data.Either 中的 isLeft 和 isRight。看起来你正在使用命令行参数,所以你可能在 IO monad 中。有像 fromLeft 和 fromRight 这样的函数,如果它们的模式匹配失败,它们会采用默认值,否则它们会解开匹配的构造函数。这看起来像fromLeft :: a -> Either a b -> a,如果您提供的a 是Right 值,那么它将被返回。你可以这样使用:
whenIsLeft :: (a -> IO ()) -> Either a b -> IO ()
whenIsLeft f e = if isLeft e then (applyToLeft f e) else pure ()
where applyToLeft func (Left x) = func x
explodeIfRight :: Either a b -> a
explodeIfRight = fromLeft (error "KABOOM")
whichHand :: Either a b -> String
whichHand e = if isLeft e then "Left!!!" else "Right :DDD"
对于whenIsLeft,f 可能类似于\err -> print err >> exitWith (ExitFailure 1)。请记住,Maybe 有一个类似的函数:fromJust,如果模式匹配失败,默认情况下会抛出错误。
你也可以用模式匹配来表达这一点,以避免if isLeft then fromLeft...:
whenIsLeft' :: (a -> IO ()) -> Either a b -> IO ()
whenIsLeft' f (Left e) = f e
whenIsLeft' _ (Right _) = pure ()
最后,前奏曲中有一个非常方便的组合函数either,它有两个函数,一个用于每个可能的“路径”。
either :: (a -> c) -> (b -> c) -> Either a b -> c
either errFunc successFunc leftOrRight =
case leftOrRight of
Left e -> errFunc e
Right x -> successFunc x
两个函数都需要返回相同的类型,因此您可以使用它来处理错误并回到正轨,或者在错误不可恢复时退出。
exitIfLeft :: Either a b -> IO ()
exitIfLeft = either (\err -> print err >> exitWith (ExitFailure 1)) (pure . const ())
一般来说,Either 形成一个 monad,如果 Either-returning 函数链失败,则该 monad 将短路,因此您通常不需要模式匹配直到最后。
例如,如果您有 3 个函数,其中任何一个都可能失败并显示错误消息:
f :: w -> Either String x
g :: x -> Either String y
h :: y -> Either String z
然后你可以像链接(组合)它们一样
fgh :: w -> Either String z
fgh w = f w >>= g >>= h
只需要在最后检查结果。
unlessZ :: w -> String
unlessZ w = case (f w >>= g >>= h) of
Left e ...
-- the ideal use case for `either`
monad 实例为您抽象出所有模式匹配/错误检查。如果您有一些只想应用到一个分支的功能,您可以使用 Control.Arrow 中的 left 和 right,或者使用 Either 的 Functor 实例在容器内映射该功能,如果值在 Right 构造函数中。
在generalgeneral 中,您在Haskell 中的控制流是由不同数据构造函数上的模式匹配决定的。只需将函数分配给数据类型的每个构造函数,您就可以构建整个处理程序系统。