对 GHC -Wall 风格的影响
使用 -Wall
启用 GHC 警告被认为是良好的做法。但是,我发现修复这些警告会对某些类型的代码构造产生负面影响。
示例 1:
如果我没有明确使用 _ <- f<,则使用与
f >>
等效的 do 表示法将生成警告/code> 形式:
Warning: A do-notation statement discarded a result of type Char.
Suppress this warning by saying "_ <- f",
or by using the flag -fno-warn-unused-do-bind
我知道我可能会忘记对 f
的结果执行某些操作。然而,忽略结果是合法的(在解析器中很常见)。使用>>
时没有任何警告,对吗?使用 _ <-
比应有的重。
示例 2:
使用与可见函数相同的名称来命名模式变量将给出:
Warning: This binding for `map' shadows the existing binding
imported from Prelude
当使用记录语法时,情况会变得更糟,因为名称空间会很快被污染。解决方案是在模式表达式中给出一个备用名称。所以我最终使用了一个不太合适的名称以避免警告。我觉得这个理由还不够充分。
我知道我可以使用 -fno-warn-...
选项,但我到底应该坚持使用 -Wall
吗?
It is considered good practice to enable GHC warnings with -Wall
. However, I've found out that fixing those warnings has a negative effect for some types of code constructs.
Example 1:
Using the do-notation equivalent of f >>
will generate a warning if I don't explicitly use the _ <- f
form:
Warning: A do-notation statement discarded a result of type Char.
Suppress this warning by saying "_ <- f",
or by using the flag -fno-warn-unused-do-bind
I understand that I can forget to do something with the result of f
. However, it is legitimate to ignore the result (very common in parsers). There is no warning when using >>
, right? Using _ <-
is heavier than it should.
Example 2:
Naming a pattern variable with the same name of a visible function will give:
Warning: This binding for `map' shadows the existing binding
imported from Prelude
This is getting worse when using record syntax as namespace gets polluted quickly. The solution is to give an alternate name in the pattern expression. So I end up using a less appropriate name just to avoid a warning. I don't feel it's a good-enough reason.
I know I can use -fno-warn-...
options but should I stick with -Wall
after all?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
示例 1:
我重新学习了以应用风格编写解析器——它们更加简洁。例如,而不是:
我改为写:
但是我能说什么,如果您不喜欢这个警告,请按照它的建议禁用它。
示例 2:
是的,我发现这个警告也有点令人恼火。但它救了我几次。
它与命名约定相关。我喜欢保持模块非常小,并保持大多数导入合格(除了像
Control.Applicative
和Control.Arrow
这样的“符号”导入)。这样可以降低名称冲突的可能性,并且使工作变得更容易。如果您使用标签,hothasktags
使这种样式可以接受。如果您只是对具有相同名称的字段进行模式匹配,则可以使用
-XNamedFieldPuns
或-XRecordWildCards
来重用该名称:另一个常见约定是添加匈牙利语前缀致唱片公司:
但是,是的,在 Haskell 中使用唱片并不有趣。不管怎样,保持你的模块小并且你的抽象紧密,这应该不是问题。将其视为一个警告,上面写着simplifyyyy,伙计。
Example 1:
I have re-learned to write parsers in Applicative style -- they are much more concise. Eg, instead of:
I instead write:
But what can I say, if you don't like the warning, disable it as it suggests.
Example 2:
Yeah I find that warning a bit irritating as well. But it has saved me a couple times.
It ties into naming conventions. I like to keep modules pretty small, and keep most imports qualified (except for "notation" imports like
Control.Applicative
andControl.Arrow
). That keeps the chances of name conflict low, and it just makes things easy to work with.hothasktags
makes this style tolerable if you are using tags.If you are just pattern matching on a field with the same name, you can use
-XNamedFieldPuns
or-XRecordWildCards
to reuse the name:Another common convention is to add a hungarian prefix to record labels:
But yeah, records are no fun to work with in Haskell. Anyway, keep your modules small and your abstractions tight and this shouldn't be a problem. Consider it as a warning that says simplifyyyy, man.
我认为使用
-Wall
可能会导致代码可读性较差。特别是,如果它正在做一些算术运算。其他一些示例,其中使用
-Wall
建议进行可读性较差的修改。(^)
与-Wall
需要指数的类型签名考虑以下代码:
使用
-Wall
它会给出两个警告,如下所示:编写
(^(2::Int)
无处不在,而不是(^2)
不太好。所有顶层都需要类型签名。
当编写快速而肮脏的代码时,这很烦人。对于简单的代码,最多使用一种或两种数据类型(例如,我知道我只使用 Double ),在任何地方编写类型签名可能会使阅读变得复杂。有两个警告只是因为缺少类型签名:
作为一种干扰,其中一个是指与需要类型签名的行不同的行。
需要使用 Integral 进行中间计算的类型签名
。考虑一个例子:
用
fromIntegral
转换回Double
时,它会给出一堆警告:每个人都知道需要多长时间。 Haskell 中的
fromIntegral
...类似这样的情况还有很多,仅仅为了满足
-Wall
要求,数字代码就有变得不可读的风险。但我仍然在我想确定的代码上使用-Wall
。I think that use of
-Wall
may lead to less readable code. Especially, if it is doing some arithmetics.Some other examples, where the use of
-Wall
suggests modifications with worse readability.(^)
with-Wall
requires type signatures for exponentsConsider this code:
With
-Wall
it gives two warnings like this:Writing
(^(2::Int)
everywhere instead of(^2)
is not nice.Type signatures are required for all top-levels
When writing quick and dirty code, it's annoying. For simple code, where there are at most one or two data types in use (for exapmle, I know that I work only with
Double
s), writing type signatures everywhere may complicate reading. In the example above there are two warnings just for the lack of type signature:As a distraction, one of them refers to the line different from the one where the type signature is needed.
Type signatures for intermediate calculations with
Integral
are necessaryThis is a general case of the first problem. Consider an example:
It gives a bunch of warnings. Everywhere with
fromIntegral
to convert back toDouble
:And everyone knows how often one needs
fromIntegral
in Haskell...There are more cases like these the numeric code risks to become unreadable just to fulfill the
-Wall
requirements. But I still use-Wall
on the code I'd like to be sure of.我建议继续使用“-Wall”作为默认选项,并使用相关文件顶部的 OPTIONS_GHC 编译指示禁用本地、每个模块所需的任何检查。
我可能会例外的确实是“-fno-warn-unused-do-bind”,但一个建议可能是使用显式的“void”函数......写“void f”似乎比“_ <”更好;-f'。
至于名称隐藏 - 我认为如果可以的话最好避免 - 在某些代码中间看到“map”将导致大多数 Haskellers 期望标准库 fn。
I would recommend continuing to use '-Wall' as the default option, and disable any checks you need to on local, per-module basis using an OPTIONS_GHC pragma at the top of relevant files.
The one I might make an exception for is indeed '-fno-warn-unused-do-bind', but one suggestion might be to use an explicit 'void' function ... writing 'void f' seems nicer than '_ <- f'.
As for name shadowing - I think it's generally good to avoid if you can - seeing 'map' in the middle of some code will lead most Haskellers to expect the standard library fn.
名称隐藏可能非常危险。特别是,很难推断名称被引入的范围。
do 表示法中未使用的模式绑定并没有那么糟糕,但可能表明正在使用效率较低的函数(例如
mapM而不是
mapM_
)。正如 BenMos 指出的那样,使用
void
或ignore
显式丢弃未使用的值是一种明确表达事物的好方法。如果能够仅对一段代码而不是同时对所有代码禁用警告,那就太好了。另外,cabal 标志和命令行 ghc 标志优先于文件中的标志,因此我不能在任何地方默认使用 -Wall,甚至可以轻松地为整个单个文件禁用它。
Name shadowing can be quite dangerous. In particular, it can become difficult to reason about what scope a name is introduced in.
Unused pattern binds in do notation are not as bad, but can indicate that a less efficient function than necessary is being used (e.g.
mapM
instead ofmapM_
).As BenMos pointed out, using
void
orignore
to explicitly discard unused values is a nice way to be explicit about things.It would be quite nice to be able to disable warnings for just a section of code, rather than for everything at once. Also, cabal flags and command line ghc flags take precedence over flags in a file, so I can't have -Wall by default everywhere and even easily just disable it for the entirety of a single file.
所有这些警告都有助于防止错误,应该受到尊重,而不是压制。
如果您想使用 Prelude 中的名称定义函数,可以使用
import Prelude hide (map)
隐藏它。 “隐藏”语法只能用于 Prelude 和同一包的模块,否则您将面临因 API 更改而导致代码损坏的风险。导入的模块。
请参阅:http://www.haskell.org/haskellwiki/Import_modules_properly
All these warnings help to prevent mistakes and should be respected, not suppressed.
If you want to define a function with a name from Prelude, you can hide it using
import Prelude hiding (map)
'Hiding' syntax should only be used for Prelude and modules of the same package, otherwise you risk code breakage by API changes in the imported module.
See: http://www.haskell.org/haskellwiki/Import_modules_properly
还有侵入性较小的
-W
选项,它启用一组主要与一般编码风格相关的合理警告(未使用的导入、未使用的变量、不完整的模式匹配等)。特别是它不包括您提到的两个警告。
There is also the much less intrusive
-W
option, which enables a set of reasonable warnings mostly related to general coding style (unused imports, unused variables, incomplete pattern matches, etc.).In particular it does not include the two warnings you mentioned.