【问题标题】:How to know if it is on the left or on the right after doing a function that returns Either?在执行返回 Either 的函数后如何知道它是在左侧还是在右侧?
【发布时间】:2021-03-13 15:52:48
【问题描述】:

我是 Haskell 的新手,我想做一个函数,如果退出则返回退出,但我不知道该怎么做。H 这是我的函数,它返回:

getOpts :: Conf->[String]-> Either String Conf
getOpts Help _ = Right Help
getOpts c@Conf{} ("--start":x:xs) = readPos x >>= (\x-> getOpts c{start = x} xs)
getOpts c@Conf{} ("--lines":x:xs) = 
    readPos x >>= (\x-> getOpts c{Main.lines = x} xs)
getOpts c@Conf{} ("--window":x:xs) = 
    readPos x >>= (\x-> getOpts c{window = x} xs)
getOpts c@Conf{} ("--move":x:xs) = readPos x >>= (\x-> getOpts c{move = x} xs)
getOpts c@Conf{} ("--rules":x:xs) = 
    readMPos x >>= (\x-> getOpts c{rules = x} xs)
getOpts c []  = Right c 
getOpts _ _ = Left "Invalid Parameter!"```

【问题讨论】:

  • 这样可以吗? check :: Either a b -> IO() check a = if isleft a == true then exiwith 42
  • 使用模式匹配例如check (Left x) = exitWith ... ; check (Right y) = ....。通过这种方式,您不仅可以知道它是左值还是右值,还可以访问哪个值(在我的示例中为xy)。

标签: haskell either


【解决方案1】:

有几种方法:

如果您想显式处理结果,可以在 Either 构造函数上进行模式匹配:

foo :: Either a b -> c
foo (Left a) = <some function from (a -> c)>
foo (Right b) = <some function from (b -> c)>

如果您有一些要根据先前结果处理的条件,则可以使用 Data.Either 中的 isLeftisRight。看起来你正在使用命令行参数,所以你可能在 IO monad 中。有像 fromLeftfromRight 这样的函数,如果它们的模式匹配失败,它们会采用默认值,否则它们会解开匹配的构造函数。这看起来像fromLeft :: a -&gt; Either a b -&gt; a,如果您提供的aRight 值,那么它将被返回。你可以这样使用:

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"

对于whenIsLeftf 可能类似于\err -&gt; print err &gt;&gt; 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 中的 leftright,或者使用 EitherFunctor 实例在容器内映射该功能,如果值在 Right 构造函数中。

generalgeneral 中,您在Haskell 中的控制流是由不同数据构造函数上的模式匹配决定的。只需将函数分配给数据类型的每个构造函数,您就可以构建整个处理程序系统。

【讨论】:

    猜你喜欢
    • 2021-10-06
    • 1970-01-01
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-27
    相关资源
    最近更新 更多