Elegant Haskell case/error handling

后端 未结 2 679
悲哀的现实
悲哀的现实 2021-01-13 18:40

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, sho

相关标签:
2条回答
  • 2021-01-13 19:08

    Nested Maybes is indeed messy.

    Suggestion 1: roll a custom error type and use 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
    

    Now use Either to mix Ok values (Right) and error values (Left):

    type MyType = Either MyError Int
    

    Now 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 -> MyType
    myAdd i1 i2 = (+) <$> i1 <*> i2
    

    is nicely applicative, or

    myMult i1 i2 = do
        a <- i1
        b <- i2
        return $ a * b
    

    if you prefer monadic notation. We can use either in a crash-the-program way

    myShow :: MyType -> String
    myShow = either (error.explain) show 
    

    or a tell-me-anyway way:

    process4 :: MyType -> String
    process4 = either explain show
    

    Suggestion 2: roll a custom type

    data MyType' = OK Int | ReadError | TooBig Int
    

    and 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 monad

    Read up about Control.Monad.Error and use the supplied functions or the ErrorT monad transformer.

    0 讨论(0)
  • 2021-01-13 19:16

    I think the most readable way is the maybe function you already tried, just a little bit prettified by avoiding lambdas (pointfree style) and using maybe even for the innermost check (by replacing if with mfilter):

    import Control.Monad(mfilter)
    
    process2 :: MyType -> String
    process2 =  
      maybe "error"  $ 
      maybe "error2" $ 
      maybe "error3" 
      show . mfilter (<10) . Just 
    
    0 讨论(0)
提交回复
热议问题