GHC为什么抱怨非穷举模式? [英] Why is GHC complaining about non-exhaustive patterns?

查看:67
本文介绍了GHC为什么抱怨非穷举模式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我用GHC编译下面的代码时(使用 -Wall 标志):

 模块Main其中

数据树a = EmptyTree |节点a(树a)(树a)派生(显示)

insert ::(Ord a)=> a - >树a - >树a
插入x EmptyTree =节点x EmptyTree EmptyTree
插入x(节点左右)
| x == a =节点左右
| x < a =节点a(插入x左)右
| x> a =节点左(插入x右)

main :: IO()
main = do
let nums = [1..10] :: [Int]
印刷。 foldr insert EmptyTree $ nums

GHC抱怨 insert 不完全:

  test.hs | 6 | 1:
||警告:模式匹配不是完全的
||在'insert'的等式中:模式不匹配:_(Node _ _ _)

为什么是GHC发出此警告?很显然,GHC抱怨的模式是在 insert x(Node a left right)

解决方案

Riccardo是正确的,GHC并不推断你的卫兵不可能都是假的。所以请接受他的答案。



我会离题,谈论编码风格。因为不使用,否则可能看起来难看:

  insert ::(Ord a)=> a  - >树a  - >树a 
插入x EmptyTree =节点x EmptyTree EmptyTree
插入x(节点左右)
| x == a =节点左右
| x < a =节点a(插入x左)右
|否则=节点左(插入x右)

查看此代码,人类读者必须确认他们自己认为最后一名后卫正好接受那些 x>




insert ::(Ord a)=> a - >树a - >树a
插入x EmptyTree =节点x EmptyTree EmptyTree
插入x(节点a向左)= case x`compare` a
EQ - >节点左右
LT - >节点a(插入x左)右
GT - >节点左(插入x右)

排序比较返回的类型只有三个值 EQ LT GT ,因此GHC可以确认您已经涵盖了所有可能性,并且人类读者可以很容易地看到您正确地覆盖了它们。



这也是更高效的代码:我们调用 compare 一次,而不是调用 == ,然后可能会调用<



现在我要离题了更多,并谈论懒惰。



你也许写了一个类似于这个的函数:

  contains ::(Ord a)=> a  - >树a  - > Bool 
包含_ EmptyTree = False
包含x(Node a left right)= case x`compare` a of
EQ - > True
...

x == a ,你需要知道树使用 Node 构造函数,并且它的第一个参数等于 x 。你不需要知道任何一个子树是什么。



但现在回头看看的定义insert 以上。当它给出的树是一个 Node 时,它总是返回一个 Node ,其第一个参数总是。但它并没有说明:前者:它会评估 x`compare` a



我们可以重写插入以尽可能晚地执行比较:

  insert: (Ord a)=> a  - >树a  - >树a 
插入x EmptyTree =节点x EmptyTree EmptyTree
插入x(Node a left right)=节点newLeft newRight
其中compare = x`比较`a
newLeft = if比较== LT然后插入x left left left
newRight = if comparison == GT then insert x right else right

现在我们尽快返回 Node a 位 - 即使比较抛出错误! ---我们仍然最多进行一次比较。


When I compile the following code with GHC (using the -Wall flag):

module Main where

data Tree a = EmptyTree | Node a (Tree a) (Tree a) deriving (Show)

insert :: (Ord a) => a -> Tree a -> Tree a
insert x EmptyTree = Node x EmptyTree EmptyTree
insert x (Node a left right)
    | x == a = Node a left right
    | x < a = Node a (insert x left) right
    | x > a = Node a left (insert x right)

main :: IO()
main = do
    let nums = [1..10]::[Int]
    print . foldr insert EmptyTree $ nums

GHC complains that pattern matching in insert is non-exhaustive:

test.hs|6| 1:
||     Warning: Pattern match(es) are non-exhaustive
||              In an equation for `insert': Patterns not matched: _ (Node _ _ _)

Why is GHC issuing this warning? It is pretty obvious that the pattern GHC complains about is handled in insert x (Node a left right).

解决方案

Riccardo is correct, GHC doesn't infer that your guards can't possibly all be false. So accept his answer please.

I'm going to digress and talk about coding style.

Your motivation for not using otherwise may have been that it looks unsightly:

insert :: (Ord a) => a -> Tree a -> Tree a
insert x EmptyTree = Node x EmptyTree EmptyTree
insert x (Node a left right)
    | x == a    = Node a left right
    | x < a     = Node a (insert x left) right
    | otherwise = Node a left (insert x right)

Looking at this code, a human reader must confirm to themselves that the final guard accepts precisely those cases where x > a.

We could instead write it like this:

insert :: (Ord a) => a -> Tree a -> Tree a
insert x EmptyTree = Node x EmptyTree EmptyTree
insert x (Node a left right) = case x `compare` a of
    EQ -> Node a left right
    LT -> Node a (insert x left) right
    GT -> Node a left (insert x right)

The Ordering type returned by compare has only the three values EQ, LT, and GT, so GHC can confirm that you've covered all possibilities, and a human reader can easily see that you've covered them correctly.

This is also more efficient code: we call compare once, instead of calling == and then probably calling < as well.

Now I'm going to digress some more and talk about laziness.

You've probably also written a function similar to this:

contains :: (Ord a) => a -> Tree a -> Bool
contains _ EmptyTree = False
contains x (Node a left right) = case x `compare` a of
    EQ -> True
    ...

When x == a, you need to know that the tree uses the Node constructor, and that its first argument is equal to x. You don't need to know what either of the subtrees are.

But now look back at my definition of insert above. When the tree it's given is a Node, it always returns a Node whose first argument is always a. But it doesn't state that up front: instead it evaluates x `compare` a.

We can rewrite insert to perform the comparison as late as possible:

insert :: (Ord a) => a -> Tree a -> Tree a
insert x EmptyTree = Node x EmptyTree EmptyTree
insert x (Node a left right) = Node a newLeft newRight
  where comparison = x `compare` a
        newLeft  = if comparison == LT then insert x left  else left
        newRight = if comparison == GT then insert x right else right

Now we return the Node a bit as soon as possible --- even if the comparison throws an error! --- and we still perform the comparison once at most.

这篇关于GHC为什么抱怨非穷举模式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆