Haskell:非详尽模式 - 检查列表是否在升序

时间:2015-02-08 00:05:02

标签: haskell non-exhaustive-patterns

我不知道为什么我的功能不起作用。我已经阅读了关于非详尽功能的所有帖子,但据我所知,我的功能可以满足所有可能的选项。

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

结果:

*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

它适用于一对,但如果该对不是提升则不适用。当我按照我的代码时,应该只返回False。

1 个答案:

答案 0 :(得分:4)

仔细查看[x,y]模式的警卫:

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

当应用于[2,1]时,会检查第一个警卫并评估为False(因为2> = 1);然后,检查第二个警卫,但它也评估为False(因为1&lt; 2)。因此,使用下一个模式(因为[2,1]也匹配(x:y:ys)),但完全相同的事情发生。因为这是最后一种模式,GHC正确地尖叫着你。

你的警卫中的不平等不是互补的。你的第三个模式应该是

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

或者,为了留出更少的错误空间,

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

然而,仍有很大的改进空间。特别是:

  • 第三种模式与第四种模式重叠。
  • 因为你的函数返回Bool,所以只使用guards来显式返回一个布尔值是多余的。
  • 因为按照约定(参见dfeuer's comment),空列表被认为是升序,遇到错误时不需要抛出错误(除非你遵循自己的异想天开的惯例)。 / LI>

考虑到所有这些,你可以简单地写一下

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

最后,您可以使用andzipWith的组合来更多地压缩代码:

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