【问题标题】:Haskell: Non-exhaustive pattern - Checking if list is ascendingHaskell:非穷举模式 - 检查列表是否升序
【发布时间】:2015-02-08 00:05:02
【问题描述】:

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

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。

【问题讨论】:

  • 仔细查看比较。当使用[2, 1] 调用它时,应该关闭哪个分支?
  • @David 我原以为它会在 x = 2 和 y = 1 的情况下上升 [x, y] ......然后它点击了......我觉得自己像个白痴.好吧,现在我知道“非详尽”还包括警卫。谢谢!
  • 如果您启用警告,GHC 应该静态地发出警告。非常粗略地说,如果最后一个守卫不是otherwiseTrue,则认为case 分支不是详尽无遗的,除非下面有另一个分支捕获可能不匹配的术语,否则它将触发警告。 IMO,我希望这是一个编译时错误(如 Agda 等),以便强制程序员编写所有案例,即使其中一些只是 undefined

标签: haskell non-exhaustive-patterns


【解决方案1】:

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

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

当应用于[2,1] 时,检查第一个守卫并评估为False(因为 2 >= 1);然后,检查第二个守卫,但它也评估为False(因为 1 [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)

【讨论】:

  • 一个非常全面的答案。谢谢。
  • @deadfire19,最后,一个空列表是vacuously 升序,所以没有必要让这种情况成为错误。 ascending [] = True 会很好。或者您可以将最后一个 case 移到开头,然后创建第二个 case ascending _ = True
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多