当模式匹配时,为什么这在Haskell中是一个有用的警告?"已定义但未使用"

Duc*_*tro 20 warnings haskell pattern-matching

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

1: takeTree 0 tree                           = Leaf
2: takeTree levels (Leaf)                    = Leaf
3: takeTree levels (Branch value left right) = Branch value (takeTree...
Run Code Online (Sandbox Code Playgroud)

我特别得到两个警告:

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...
Run Code Online (Sandbox Code Playgroud)

哪个,修复了警告,我现在发现它的可读性要低得多,并且混淆了我期望作为输入值的语义.

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

Ben*_*Ben 45

如果某些东西足够重要,可以将它命名为必须足够重要,这种假设在许多编码风格中都是合理的.

但是你可以吃蛋糕并吃掉它:

takeTree 0 _tree                           = Leaf
takeTree _levels (Leaf)                    = Leaf
takeTree levels (Branch value left right)  = Branch value (takeTree...
Run Code Online (Sandbox Code Playgroud)

前导下划线的名义信号在人类读者和这个名字并不打算在这个公式中使用的编译器,但这个名字比单下划线长仍可以传达更多的意义的人.


Chr*_*ris 35

我发出了这个警告所指出的编码错误.简化示例:

fun x xs = go xs
  where
    go []      = ... 
    go (y:xs') = f y (go xs)
Run Code Online (Sandbox Code Playgroud)

xs'当然,递归调用应该具有参数,并且"已定义但未使用"警告将捕获该警告.对我而言,使用_进行未使用的匹配是不方便的.

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

另请参阅Ben的答案:您可以使用_name名称但仍然禁止警告.

  • 而这种错误实际上并不罕见,也不是微不足道的.因为素数变体通常与非素数变体非常相似,所以它永远不是类型错误,并且通常很难在运行时调试中发现,就像很难发现缺少的`'`本身.+1 (12认同)

Stu*_*etz 9

编译器试图建议您使用某种编码风格.如果你不喜欢它(足够公平),就有办法避免这个问题.见例如:

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

至于问题的实质(这是否是一个有用的警告):在这种情况下命名变量的缺点是它表明名称对编译器有意义,而不是.有利的一面,当你正确地指出,是他们对人类有意义.基本上有一个权衡,这是非常主观的.重要的是,如果需要,您可以获得所需的行为.