Haskell: Non-exhaustive pattern - Checking if list is ascending

回眸只為那壹抹淺笑 提交于 2019-12-13 01:27:26

问题


I have no idea why my function doesn't work. I have gone through all the posts about non-exhaustive functions but my functions fulfills all possible options as far as I can see.

ascending :: [Int] -> Bool
ascending []                = error "Empty list given"
ascending [x]               = True
ascending [x,y]     | y>=x  = True
                    | x<y   = False
ascending (x:y:xs)  | y>=x  = (ascending (y:xs))
                    | x<y   = False

Result:

*Main> ascending []
*** Exception: Empty list given
*Main> ascending [1]
True
*Main> ascending [1, 2]
True
*Main> ascending [2, 1]
*** Exception: test01.hs:(51,1)-(56,55): Non-exhaustive patterns in function ascending

It works for one pair, but not if the pair is not ascending. When I follow my code it should be just returning False.


回答1:


Have a closer look at the guards for your [x,y] pattern:

ascending [x,y] | y>=x = True
                | x<y  = False

When applied to [2,1], the first guard is checked and evaluates to False (because 2 >= 1); then, the second guard is checked, but it also evaluates to False (because 1 < 2). Therefore, the next pattern is used (because [2,1] also matched (x:y:ys)), but exactly the same thing happens. Because this was the last pattern, GHC rightfully screams at you.

The inequalities in your guards are not complementary. Your third pattern should read

ascending [x,y] | x <= y = True
                | x >  y = False

or, to leave less room for error,

ascending [x,y] | x <= y    = True
                | otherwise = False

However, there is still much room for improvement. In particular:

  • The third pattern overlaps with the fourth one.
  • Because your function returns a Bool, using guards only to explicitly return a Boolean value is redundant.
  • Because, by convention (see dfeuer's comment), the empty list is considered to be ascending, you don't need to throw an error upon encountering it (unless you're following your own whimsical convention).

Taking all this into account, you could have simply written

ascending :: [Int] -> Bool
ascending (x:y:xs) = x <= y && ascending (y:xs)
ascending _        = True

Finally, you can condense the code some more with a combination of and and zipWith:

ascending :: [Int] -> Bool
ascending xs = and $ zipWith (<=) xs (tail xs)


来源:https://stackoverflow.com/questions/28389008/haskell-non-exhaustive-pattern-checking-if-list-is-ascending

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!