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

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

我不知道为什么我的功能不起作用。我浏览了所有关于非详尽函数的帖子,但据我所知,我的函数满足了所有可能的选项。

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。

仔细看看你的 [x,y] 模式的守卫:

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

当应用于[2,1]时,第一个守卫被检查并评估为False(因为2 >= 1);然后,检查第二个守卫,但它的计算结果也为 False(因为 1 < 2)。因此,使用了下一个模式(因为 [2,1] 也匹配 (x:y:ys)),但发生了完全相同的事情。因为这是最后一个模式,GHC 理所当然地向你尖叫。

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

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

或者,为了减少出错的空间,

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

不过,还有很大的改进空间。特别是:

  • 第三个模式与第四个重叠。
  • 因为您的函数 return 是一个 Bool,仅使用守卫来显式 return 布尔值是多余的。
  • 因为按照惯例(见),空列表被认为是升序的,你不需要在遇到它时抛出错误(除非你遵循你自己异想天开的惯例) .

考虑到所有这些,您可以简单地写成

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)