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

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

问题描述

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

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 抱怨 insert 中的模式匹配并不详尽:

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 _ _ _)

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

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 是对的,GHC 不会推断您的守卫不可能全部都是假的.所以请接受他的回答.

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)

查看此代码,人类读者必须向自己确认最终守卫接受的情况正是 x >一个.

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

我们可以这样写:

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)

compare 返回的 Ordering 类型只有 EQLT 三个值GT,因此 GHC 可以确认您已涵盖所有可能性,并且人类读者可以轻松看出您已正确涵盖它们.

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.

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

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
    ...

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

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.

但现在回头看看我上面对 insert 的定义.当它给定的树是一个 Node 时,它总是返回一个 Node,它的第一个参数总是 a.但它并没有预先说明:而是评估 x `compare` a.

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.

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

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

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

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天全站免登陆