我正在努力更好地理解如何处理haskell中的错误情况,并编写了一些代码来帮助我。
处理多个替代方案(如嵌套案例表达式)是否有更好的方法(更优雅,更简洁,更通用)?有关该主题的任何不错的教程?
此示例的伪造类型。
这有点简化,因为大多数不仅有这些嵌套
类型但依赖值只能按顺序检索(例如
从stdin读取id,然后从a中检索此id的记录
数据库)。 因此,此处的嵌套应该演示一种情况,即只有在Nothing
已经检查外部值时,内部值才可用。有关更好的示例,请参阅我的new question。
type MyType = (Maybe (Maybe Int))
当小于10时返回int,在其他情况下(更大或更大) 等于10,Nothing或Just Nothing)返回不同的错误消息。
process Nothing ~> "error"
process (Just Nothing) ~> "error2"
process (Just (Just 20)) ~> "error3"
process (Just (Just 5)) ~> "5"
患有“匍匐缩进”
process :: MyType -> String
process t = case t of
Nothing -> "error"
Just a -> case a of
Nothing -> "error2"
Just b -> if b < 10 then show b else "error3"
使用Maybe函数,这会使它更短但也更难阅读。
process2 :: MyType -> String
process2 t = maybe "error" (\a -> maybe "error2" (\b -> if b < 10 then show b else "error3") a) t
目前为止最好的解决方案,但在更复杂的情况下是不可能的 case(请参阅MyType类型定义上面的注释)。
process3 :: MyType -> String
process3 Nothing = "error"
process3 (Just Nothing) = "error2"
process3 (Just (Just a))
| a < 10 = show a
| otherwise = "error3"
下找到包含该代码的要点
答案 0 :(得分:4)
嵌套Maybes
确实很乱。
Either
data MyError = ReadError | TooBig Int
explain :: MyError -> String
explain ReadError = "Error: the requested Int could not be found"
explain TooBig i = "Error: the supplied Int should be at most 10, but it was " ++ show i
现在使用Either来混合Ok值(右)和错误值(Left):
type MyType = Either MyError Int
现在有许多方便的功能,如either
和Either a
的Applicative和Monad实例,可以轻松编写出色的代码:
myAdd :: MyType -> MyType -> MyType
myAdd i1 i2 = (+) <$> i1 <*> i2
非常适用,或
myMult i1 i2 = do
a <- i1
b <- i2
return $ a * b
如果您更喜欢monadic符号。
我们可以以程序崩溃的方式使用either
myShow :: MyType -> String
myShow = either (error.explain) show
或告诉我 - 无论如何:
process4 :: MyType -> String
process4 = either explain show
data MyType' = OK Int | ReadError | TooBig Int
并使用模式匹配。这不像我的观点中的建议1那么好,因为你失去了高阶函数重用,但它优于Maybe (Maybe Int)
阅读Control.Monad.Error并使用提供的函数或ErrorT
monad变换器。
答案 1 :(得分:1)
我认为最可读的方式是你已经尝试的maybe
函数,通过避免lambdas(无点样式)和使用maybe
进行最内部检查(通过替换{{ 1}}与if
):
mfilter