haskell - 在执行返回 Either 的函数后如何知道它是在左侧还是在右侧?
问题描述
我是 Haskell 的新手,我想做一个函数,如果它离开则返回退出,但我不知道该怎么做。这是我的函数,它返回:
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!"```
解决方案
有几种方法:
如果要显式处理结果,可以在Either
构造函数上进行模式匹配:
foo :: Either a b -> c
foo (Left a) = <some function from (a -> c)>
foo (Right b) = <some function from (b -> c)>
如果您有一些要根据先前结果处理的条件,则可以使用isLeft
and isRight
from 。Data.Either
看起来你正在使用命令行参数,所以你可能在 IO monad 中。有类似fromLeft
and的函数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
如果一连串的 -returning 函数失败,它会形成一个短路的 monad Either
,所以你通常不需要模式匹配直到最后。
例如,如果您有 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
and ,或者如果值在构造函数内,则使用for 的实例将该函数映射到容器内。right
Functor
Either
Right
一般来说,Haskell 中的控制流是由不同数据构造函数的模式匹配决定的。您可以通过将函数分配给数据类型的每个构造函数来构建整个处理程序系统。
推荐阅读
- python - MPI - Python Anaconda 中的 HelloWorld 程序
- ios - 错误域=CBATTErrorDomain 代码=2“不允许读取。” UserInfo={NSLocalizedDescription=不允许读取。}
- git - “git stash”后无法恢复本地更改
- reactjs - 为什么我在使用 redux 时收到 TypeError: Object(...) is not a function 错误?
- sonarqube - SonarQube Jacoco 覆盖率报告 (.ec & xml) 报告未一起显示
- vue.js - 在 vue js mdb footer get break 如何解决这个问题?
- button - 响应多次鼠标点击以产生不同的输出 - Tkinter
- jquery - 使用 CSS-transition 从右到左移动 div
- python - 如何通过迭代python中的for循环来动态构建变量
- python - 当我们扩展一个 allauth 视图并基于该视图创建一个新的 url 时,django allauth 的旧的“/accounts/*” URL 是否仍然需要?