在为函数定义多个模式匹配时,例如如下:
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
在这里是一个合理的警告,当我的详尽模式中,每个参数实际上至少使用过一次?
答案 0 :(得分:45)
假设如果某些东西足够重要而且必须足够重要,那么在许多编码风格中使用它是合理的。
但你可以吃蛋糕并吃掉它:
takeTree 0 _tree = Leaf
takeTree _levels (Leaf) = Leaf
takeTree levels (Branch value left right) = Branch value (takeTree...
名称中的前导下划线表示两者人类读者和编译器,该名称不打算在此等式中使用,但名称长于单个下划线仍可传达对人类更有意义。
答案 1 :(得分:34)
我发出了这个警告所指出的编码错误。简化示例:
fun x xs = go xs
where
go [] = ...
go (y:xs') = f y (go xs)
当然,递归调用应该以{{1}}作为参数,并且“已定义但未使用”警告将捕获该警告。对我来说,使用_来处理未使用的匹配是不方便的。
编译器无法猜测您的意图,并且您在另一场比赛中使用该参数的事实并不意味着您不打算在产生警告的匹配中使用它。毕竟,你可以使用xs'
,所以你没有的警告是合理的。
另请参阅Ben的答案:您可以使用tree
来使用名称,但仍会取消警告。
答案 2 :(得分:9)
编译器试图建议您使用某种编码风格。如果你不喜欢它(足够公平),就有办法避免这个问题。参见例如:
How to [temporarily] suppress "defined but not used" warnings?
关于问题的实质(这是否是一个有用的警告):在这种情况下命名变量的缺点是它表明名称对于编译器是有意义的,当它们不是时。正如你正确指出的那样,好处是它们对人类有意义。基本上有一个权衡,这是非常主观的。重要的是,如果需要,您可以获得所需的行为。