当前位置:  开发笔记 > 编程语言 > 正文

是否建议在Haskell中始终使用详尽的模式匹配,即使是"不可能"的情况?

如何解决《是否建议在Haskell中始终使用详尽的模式匹配,即使是"不可能"的情况?》经验,为你挑选了3个好方法。

是否建议在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

模式不匹配(由解释器报告)是:

警告:模式匹配是非详尽的在案例替代方案中:模式不匹配:[]:_



1> bdonlan..:

这可能更像是风格问题而不是其他任何问题.就个人而言,我会投入一个

_ -> error "Impossible! Empty list in step"

如果只是沉默警告:)


当您的程序突然终止此描述性消息时,它总是很有趣:***例外:不可能发生!
我同意这种方法.它有助于表明你故意不处理其他情况,因为你认为这是不可能的,而不是你只是忘记或没有意识到.

2> Christoph..:

您可以通过执行以下操作解决此特殊情况下的警告:

gb_groupBy p input = foldr step [] input
   where
     step item acc = case acc of
        []                           -> [[item]]
        (xs:xss)                      -> if p (head xs) item
                                         then  (item:xs):xss
                                         else [item]:acc

然后完成模式匹配,并且累加器开头的空列表的"不可能"条件将导致运行时错误但没有警告.

查看不完整模式匹配的更一般问题的另一种方法是将它们视为"代码气味",即表示我们试图以次优或非Haskellish方式解决问题,并尝试重写我们的功能.

使用foldr实现groupBy使得无法将其应用于无限列表,这是Haskell List函数在语义上合理的任何地方尝试实现的设计目标.考虑

take 5 $ groupBy (==) someFunctionDerivingAnInfiniteList

如果前5个组相等是有限的,则延迟评估将终止.这是您不能用严格评估的语言做的事情.即使您不使用无限列表,编写这样的函数也会在长列表上产生更好的性能,或者避免在评估表达式时出现的堆栈溢出

take 5 $ gb_groupBy (==) [1..1000000]

在List.hs中,groupBy实现如下:

groupBy         :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy _  []       =  []
groupBy eq (x:xs)   =  (x:ys) : groupBy eq zs
                           where (ys,zs) = span (eq x) xs

这使得解释器/编译器仅能够评估结果所需​​的计算部分. span产生一对列表,其中第一个由列表头部的(连续)元素组成,所有元素都满足谓词,第二个列表是列表的其余部分.它也被实现为在无限列表上工作.



3> Norman Ramse..:

我发现详尽无遗地检查案例模式是不可或缺的.我尝试永远不要_在顶级案例中使用,因为_匹配所有内容,并且通过使用它,你会耗尽详尽检查的价值.这对于列表来说不那么重要,但对于用户定义的代数数据类型来说非常重要,因为我希望能够添加一个新的构造函数,并在所有缺失的情况下使用编译器barf.出于这个原因,我总是-Werror打开编译,所以我无法遗漏案例.

如上所述,您可以使用此案例扩展代码

[] : _ -> error "this can't happen"

在内部,GHC有一个panic函数,它不同于error给出源坐标,但是我查看了实现并且无法做出它的头部或尾部.


我真的很喜欢这个作为指导.在用C#编程时,我经常希望得到类似"穷举检查"的东西.例如,如果我有一个枚举和一个case语句来处理每个枚举成员,我希望能够告诉编译器"确保我已经覆盖了所有的情况".我不知道这样的概念会成为Haskell和其他功能语言基础的一部分.
推荐阅读
郑小蒜9299_941611_G
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有