本文介绍了优雅的Haskell案例/错误处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我试图更好地理解如何处理haskell中的错误情况,并编写了一些代码来帮助我。 是否有更好的处理多个替代方法(如嵌套的case表达式)的方式(更优雅,更短,更通用)?任何有关该主题的漂亮教程? 此示例的组合类型。 这有点简化,因为大多数不仅有这些嵌套的类型,而且只能依次检索相关值(例如从stdin读取一个id,然后检索该id的记录从数据库)。 因此,这里的嵌套应该演示一个情况,只有当外部值已经被检查为 Nothing 时,内部值才可用。有关更好的示例,请参阅我的新问题。 type MyType =(Maybe(Maybe Int)) 在其他情况下返回int(大于或等于$ b) $ b等于10,Nothing或Just Nothing)会返回不同的错误消息。 process Nothing〜> 错误进程(Just Nothing)〜> error2 process(Just(Just 20))〜> error3 process(Just(Just 5))〜> 5 到目前为止: Naiive实现 遭遇爬行缩进 过程:: MyType - > String process t = case $ t Nothing - > 错误只是 - >案例a 无 - > error2只需b - >如果b 也许函数 $ b $ 使用maybe函数可以缩短阅读时间,但也更难阅读。 process2 :: MyType - >字符串 process2 t =也许错误(\ a - >也许是error2(\ b - >如果b 模式匹配 迄今为止最好的解决方案,但不可行在更复杂的情况下(请参阅上面的MyType类型定义的注释)。 process3 :: MyType - > String process3 Nothing =error process3(Just Nothing)=error2 process3(Just(Just a)) | a< 10 =显示 |否则=error3 代码的要点可以在 https://gist.github.com/4024395 解决方案 嵌套 Maybes 确实很乱。 建议1:滚动自定义错误类型和使用或者 data MyError = ReadError | TooBig Int explain :: MyError - > 解释TooBig i =错误:提供的Int应该最多为10,但它是++ show i 现在使用Either混合OK值(右)和错误值(左): type MyType = MyError Int 或者,以及适用于的Applicative和Monad实例,或者都可以很容易地编写好的代码: myAdd :: MyType - > MyType - > MyType myAdd i1 i2 =(+)< $> i1 * i2 非常适用,或者 myMult i1 i2 = do a b return $ a * b 如果您更喜欢monadic notation。 我们可以使用或者以程序崩溃的方式使用 myShow :: MyType - >字符串 myShow =任何一个(error.explain)显示 方式: process4 :: MyType - >字符串 process4 =解释显示 建议2:滚动自定义类型 data MyType'= OK Int | ReadError | TooBig Int 并使用模式匹配。这在我的观点中并不像建议1那么好,因为你失去了高阶函数重用,但它比 Maybe(Maybe Int) $ b更好 $ b 建议3:使用Error monad 阅读关于 Control.Monad.Error 并使用提供的函数或 ErrorT monad变压器。 I'm trying to better understand how to handle error cases in haskell and made wrote some code to help me with that.Is there a better way (more elegant, shorter, more generic) of handling multiple alternatives (like nested case expressions)? Any nice tutorials about the topic?A made-up type for this example.This is a bit simplified because mostly there are not only these nestedtypes but dependent values which can only be retrieved sequentially (e.g.reading an id from stdin, then retrieving the record for this id from adatabase). So the nesting here should demonstrate a case where the inner value will only be available when the outer value is already checked for Nothing. Please see my new question for a better example.type MyType = (Maybe (Maybe Int))The goalReturn the int when it is less than 10, on other cases (greater orequal 10, Nothing or Just Nothing) return diferent error messages.process Nothing ~> "error"process (Just Nothing) ~> "error2"process (Just (Just 20)) ~> "error3"process (Just (Just 5)) ~> "5"Tried so far:Naiive implementation.Suffers from "creeping indentation"process :: MyType -> Stringprocess t = case t of Nothing -> "error" Just a -> case a of Nothing -> "error2" Just b -> if b < 10 then show b else "error3"maybe functionUsing the maybe function, which makes it shorter but also harder to read.process2 :: MyType -> Stringprocess2 t = maybe "error" (\a -> maybe "error2" (\b -> if b < 10 then show b else "error3") a) tPattern matchingNicest solution so far but is not possible in more complexcases (see comment above type definition of MyType).process3 :: MyType -> Stringprocess3 Nothing = "error"process3 (Just Nothing) = "error2"process3 (Just (Just a)) | a < 10 = show a | otherwise = "error3"A gist with the code can be found under https://gist.github.com/4024395 解决方案 Nested Maybes is indeed messy.Suggestion 1: roll a custom error type and use Eitherdata MyError = ReadError | TooBig Intexplain :: MyError -> Stringexplain 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 iNow use Either to mix Ok values (Right) and error values (Left):type MyType = Either MyError IntNow lots of handy functions like either and the Applicative and Monad instances for Either a make it easy to write nice code:myAdd :: MyType -> MyType -> MyTypemyAdd i1 i2 = (+) <$> i1 <*> i2is nicely applicative, or myMult i1 i2 = do a <- i1 b <- i2 return $ a * bif you prefer monadic notation.We can use either in a crash-the-program waymyShow :: MyType -> StringmyShow = either (error.explain) show or a tell-me-anyway way:process4 :: MyType -> Stringprocess4 = either explain showSuggestion 2: roll a custom typedata MyType' = OK Int | ReadError | TooBig Intand use pattern matching. This isn't as nice as suggestion 1 in my veiw, because you lose the higher order function reuse, but it's better than Maybe (Maybe Int)Suggestion 3: Use the Error monadRead up about Control.Monad.Error and use the supplied functions or the ErrorT monad transformer. 这篇关于优雅的Haskell案例/错误处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 10-25 05:42