2015-02-08 46 views
1

我不知道为什么我的函数不起作用。我已经浏览了所有关于非详尽功能的帖子,但是我的功能尽可能地实现了所有可能的选项。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。

+0

@jubobs是没有被[x,y]和[x]覆盖?如果有0,1,2,3+条款,那么每件事都有前进的道路。此外,为什么只有非升序(错误)列表失败? – deadfire19 2015-02-08 00:12:25

+2

仔细查看比较结果。使用'[2,1]'调用哪个分支时应该关闭? – 2015-02-08 00:12:40

+0

@David我会认为它会下降[x,y] x = 2和y = 1 .....然后点击....我觉得自己像一个白痴。那么现在我知道'非穷举'也包括守卫。谢谢! – deadfire19 2015-02-08 00:18:10

回答

3

有一个在警卫细看您[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's comment),空列表被认为是升序,所以在遇到它时(除非你遵循你自己的异想天开的约定),你不需要抛出错误。

考虑到所有这些因素,你可以简单地写

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) 
+1

非常全面的答案。谢谢。 – deadfire19 2015-02-08 00:47:55

+2

@ deadfire19,最后终于,一个空的列表[空洞](https://en.wikipedia.org/wiki/Vacuous_truth)上升,所以没有必要让这种情况出错。 '升序[] =真'会做得很好。或者,您可以将最后一个案例移至开头,然后创建第二个案例'升序_ = True'。 – dfeuer 2015-02-08 04:31:58