是否建议在Haskell中始终使用详尽的模式匹配,即使是“不可能”的情况?
例如,在下面的代码中,我在foldr的“累加器”上进行模式匹配 . 我完全控制累加器的内容,因为我创建它(它不作为输入传递给我,而是在我的函数中构建) . 因此,我知道某些模式永远不应该匹配它 . 如果我努力永远不会得到“模式匹配是非穷尽的”错误,那么我会为它设置一个模式匹配,只是错误的消息“这个模式应该永远不会发生” . 很像C#中的断言 . 我想不出别的事情 .
在这种情况下你会推荐什么做法?为什么?
这是代码:
gb_groupBy p input = foldr step [] input
where
step item acc = case acc of
[] -> [[item]]
((x:xs):ys) -> if p x item
then (item:x:xs):ys
else [item]:acc
模式不匹配(由解释器报告)是:
警告:模式匹配是非详尽的在案例替代方案中:模式不匹配:[]:_
6 回答
这可能更像是风格问题而不是其他任何问题 . 就个人而言,我会投入一个
如果只是沉默警告:)
您可以通过执行以下操作解决此特殊情况下的警告:
然后完成模式匹配,并且累加器开头的空列表的“不可能”条件将导致运行时错误但没有警告 .
查看不完整模式匹配的更一般问题的另一种方法是将它们视为“代码气味”,即表示我们试图以次优或非Haskellish方式解决问题,并尝试重写我们的功能 .
使用foldr实现groupBy使得无法将其应用于无限列表,这是Haskell List函数在语义上合理的任何地方尝试实现的设计目标 . 考虑
如果前5组w.r.t.平等是有限的,懒惰的评估将终止 . 这是您不能用严格评估的语言做的事情 . 即使您不使用无限列表,编写这样的函数也会在长列表上产生更好的性能,或者避免在评估表达式时出现的堆栈溢出
在List.hs中,groupBy实现如下:
这使得解释器/编译器仅能够评估结果所需的计算部分 . span产生一对列表,其中第一个由列表头部的(连续)元素组成,所有元素都满足谓词,第二个列表是列表的其余部分 . 它也被实现为在无限列表上工作 .
我发现详尽无遗地检查案例模式是不可或缺的 . 我尝试永远不要在顶级案例中使用
_
,因为_
匹配所有内容,并且通过使用它,您将耗尽穷举检查的 Value . 这对于列表来说不那么重要,但对于用户定义的代数数据类型来说非常重要,因为我希望能够添加一个新的构造函数,并在所有缺失的情况下使用编译器barf . 出于这个原因,我总是编译-Werror
打开,所以我无法遗漏一个案例 .如上所述,您可以使用此案例扩展代码
在内部,GHC有一个
panic
函数,与error
不同,它会给出源坐标,但是我查看了实现并且不能使它的头部或尾部 .为了跟进我之前的评论,我意识到有一种方法可以确认丢失的情况,但仍然会得到文件/行号的有用错误 . 它只会出现在未经优化的构建中(参见here) .
类型系统是你的朋友,警告让你知道你的功能有裂缝 . 最好的方法是在类型之间寻求更清晰,更优雅的配合 .
考虑ghc对
groupBy
的定义:我的观点是,一个不可能的案例是不确定的 .
如果它未定义,我们有一个函数:狡猾地命名为undefined .
完成与以下类似的匹配:
你有它!