Haskell:非穷举模式-检查列表是否为升序



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

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

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

  • 第三种图案与第四种图案重叠
  • 因为函数返回Bool,所以只使用保护显式返回布尔值是多余的
  • 因为,按照惯例(见dfeuer的评论),空列表被认为是升序的,所以你不需要在遇到它时抛出错误(除非你遵循自己异想天开的惯例)

考虑到这一切,你可以简单地编写

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)

相关内容

  • 没有找到相关文章

最新更新