20

在为一个函数定义多个模式匹配时,例如如下:

1: takeTree 0 tree                           = Leaf
2: takeTree levels (Leaf)                    = Leaf
3: takeTree levels (Branch value left right) = Branch value (takeTree...

我特别收到两个警告:

Source.hs:1:警告:已定义但未使用:`tree'

Source.hs:2:警告:已定义但未使用:`levels'

不过,我并没有立即相信这些是有用的警告。如果我的代码是:

1: takeTree 0 _                              = Leaf
2: takeTree _ (Leaf)                         = Leaf
3: takeTree levels (Branch value left right) = Branch value (takeTree...

其中,修复了警告,我现在发现它的可读性要差得多,并且混淆了我期望作为输入值的语义。

为什么Defined but not used在我的详尽模式中每个参数实际上至少使用一次时,这里根本是一个合理的警告?

4

3 回答 3

45

如果某件事足够重要而可以命名,那么它就必须足够重要以供使用,这种假设在许多编码风格中都是合理的。

但你也可以吃蛋糕:

takeTree 0 _tree                           = Leaf
takeTree _levels (Leaf)                    = Leaf
takeTree levels (Branch value left right)  = Branch value (takeTree...

The leading underscore in the name signals to both the human reader and the compiler that the name is not intended to be used in this equation, but the name being longer than a single underscore can still convey more meaning to the human.

于 2013-01-14T00:29:47.730 回答
35

我犯了这个警告指出的编码错误。简化示例:

fun x xs = go xs
  where
    go []      = ... 
    go (y:xs') = f y (go xs)

当然,递归调用应该xs'作为参数,并且“已定义但未使用”的警告会捕捉到这一点。对我来说,将 _ 用于未使用的匹配项是值得的。

编译器无法猜测您的意图,并且您在另一个匹配项中使用该参数这一事实并不意味着您无意在生成警告的匹配项中使用它。毕竟,你可以使用tree,所以你没有使用的警告是合理的。

另请参阅 Ben 的答案:您可以使用_name名称但仍会抑制警告。

于 2013-01-13T23:46:53.017 回答
9

编译器试图建议您使用某种编码风格。如果你不喜欢它(很公平),有一种方法可以避免这个问题。参见例如:

如何[暂时]抑制“已定义但未使用”的警告?

至于事情的实质(这是否是一个有用的警告):在这种情况下命名变量的缺点是它表明名称对编译器有意义,而实际上它们没有意义。正如您正确指出的那样,好处是它们人类有意义。基本上有一个权衡,这是相当主观的。重要的是,如果需要,您可以获得所需的行为。

于 2013-01-13T23:24:57.373 回答