Haskell 对GHC墙样式的影响

Haskell 对GHC墙样式的影响,haskell,coding-style,warnings,compiler-warnings,ghc,Haskell,Coding Style,Warnings,Compiler Warnings,Ghc,使用-Wall启用GHC警告被认为是良好的做法。但是,我发现修复这些警告对某些类型的代码构造有负面影响 示例1: 如果我没有明确使用\up>示例1: 我重新学会了用应用程序风格编写解析器——它们更加简洁。例如,代替: funCallExpr :: Parser AST funCallExpr = do func <- atom token "(" arg <- expr token ")" return $ FunCall func arg

使用
-Wall
启用GHC警告被认为是良好的做法。但是,我发现修复这些警告对某些类型的代码构造有负面影响


示例1:


如果我没有明确使用
\up>示例1:

我重新学会了用应用程序风格编写解析器——它们更加简洁。例如,代替:

funCallExpr :: Parser AST
funCallExpr = do
    func <- atom
    token "("
    arg <- expr
    token ")"
    return $ FunCall func arg
另一个常见惯例是在唱片标签上添加匈牙利语前缀:

data Foo = Foo { fooBaz :: Int, fooBar :: String }

但是是的,在哈斯凯尔和唱片一起工作没有乐趣。无论如何,保持你的模块小,你的抽象严密,这不应该是一个问题。把它当作一个警告,说Simulyyyy,man。< /P> < P>我建议继续使用“-WALL”作为默认选项,并禁用任何需要检查的地方,每一个模块的基础上使用opthsgHG-PracMa在相关文件的顶部。< /P>
我可能会例外的是“-fno warn unused do bind”,但有一个建议可能是使用显式的“void”函数。。。写“void f”似乎比写“Name shadowing”更好,名字阴影可能相当危险。特别是,很难对名称引入的范围进行推理

do表示法中未使用的模式绑定没有那么糟糕,但可能表明正在使用效率低于所需的函数(例如
mapM
而不是
mapM

正如BenMos所指出的,使用
void
ignore
来显式地丢弃未使用的值是一种很好的显式方式


如果能够只对一段代码禁用警告,而不是同时对所有代码禁用警告,那就太好了。此外,阴谋集团标志和命令行ghc标志优先于文件中的标志,因此默认情况下,我不能在任何地方都使用-Wall,甚至可以轻松地在单个文件中禁用它。

我认为使用
-Wall
可能会导致代码可读性降低。特别是,如果它正在做一些算术

其他一些示例中,使用
-Wall
表示修改的可读性较差

(^)
-墙
需要指数的类型签名 考虑以下代码:

norm2 x y = sqrt (x^2 + y^2)
main = print $ norm2 1 1
对于
-Wall
,它会给出如下两个警告:

rt.hs:1:18:
    Warning: Defaulting the following constraint(s) to type `Integer'
             `Integral t' arising from a use of `^' at rt.hs:2:18-20
    In the first argument of `(+)', namely `x ^ 2'
    In the first argument of `sqrt', namely `(x ^ 2 + y ^ 2)'
    In the expression: sqrt (x ^ 2 + y ^ 2)
到处写
(^(2::Int)
而不是
(^2)
是不好的

所有顶层都需要类型签名 当编写快速而肮脏的代码时,这很烦人。对于使用最多一种或两种数据类型的简单代码(例如,我知道我只使用
Double
s),在任何地方编写类型签名都可能会使阅读复杂化。在上面的示例中,有两个警告仅针对缺少类型签名:

rt.hs:1:0:
    Warning: Definition but no type signature for `norm2'
             Inferred type: norm2 :: forall a. (Floating a) => a -> a -> a
...

rt.hs:2:15:
    Warning: Defaulting the following constraint(s) to type `Double'
             `Floating a' arising from a use of `norm2' at rt.hs:2:15-23
    In the second argument of `($)', namely `norm2 1 1'
    In the expression: print $ norm2 1 1
    In the definition of `main': main = print $ norm2 1 1
作为一种干扰,其中一行与需要类型签名的行不同

需要使用
积分进行中间计算的类型签名

这是第一个问题的一般情况。考虑一个例子:

stripe x = fromIntegral . round $ x - (fromIntegral (floor x))
main = mapM_ (print . stripe) [0,0.1..2.0]
它给出了一系列警告。使用
from integral
到处转换回
Double

rt2.hs:1:11:
    Warning: Defaulting the following constraint(s) to type `Integer'
             `Integral b' arising from a use of `fromIntegral' at rt2.hs:1:11-22
    In the first argument of `(.)', namely `fromIntegral'
    In the first argument of `($)', namely `fromIntegral . round'
    In the expression:
            fromIntegral . round $ x - (fromIntegral (floor x))
每个人都知道在Haskell中需要积分的频率是多少



像这样的情况还有很多,仅仅为了满足
-Wall
的要求,数字代码就有可能变得不可读。但我仍然对我想确定的代码使用
-Wall

所有这些警告都有助于防止错误,应该得到尊重,而不是压制。 如果要使用Prelude中的名称定义函数,可以使用

导入前奏隐藏(地图)

“隐藏”语法应仅用于同一软件包的Prelude和模块,否则可能会因导入模块中的API更改而导致代码损坏


请参阅:

还有一个侵入性小得多的
-W
选项,它支持一组合理的警告,这些警告主要与常规编码样式有关(未使用的导入、未使用的变量、不完整的模式匹配等)


特别是,它没有包括您提到的两个警告。

您能提供更多关于
-Wall
影响的示例吗?例如,穷尽性检查似乎值得付出代价,但我同意,特别是在最后一点上,该选项使有效表达式复杂化。“示例1”最近才成为一个警告,并且更改不是普遍流行。人们似乎添加了-fno warn unused do绑定到他们的阴谋集团文件以禁用它。查看此邮件线程:将来请一次问一个问题。如果出现两个答案,每个答案都回答得很好,会怎么样?你会接受哪一个?@luqui我使用了两个示例来说明
-Wall
对风格有影响。我并不是在为每一个问题寻找答案。确实有一个问题:我应该坚持使用
-Wall
@Dario吗?我同意进行详尽的模式检查。我已经问过这个问题:是的,我确实想发展到应用程序解析。我还是有点太生疏了。我倾向于使用完整的单词,而不是字母或缩写模式匹配表达式中的变量。我相信这会增加冲突的风险。在我的情况下,使用合格的导入可能会很有用。我来自OOP世界,所以使用记录语法对我来说是很自然的事情。我不清楚如何重新连接大脑以执行其他操作。也许这将是StackOverflow som的另一个问题e day…我承认:我使用
map
只是为了触发警告。当我想使用
printf
时,总是会发生这种情况。无法停止此警告。但是函数
void=(>>return())
会很好。
void
有4个字符长。
默认设置很可怕,但是,是的,必须处理它也很可怕。我不认为修复这些问题会使代码不可读,只是稍微多一点
rt.hs:1:18:
    Warning: Defaulting the following constraint(s) to type `Integer'
             `Integral t' arising from a use of `^' at rt.hs:2:18-20
    In the first argument of `(+)', namely `x ^ 2'
    In the first argument of `sqrt', namely `(x ^ 2 + y ^ 2)'
    In the expression: sqrt (x ^ 2 + y ^ 2)
rt.hs:1:0:
    Warning: Definition but no type signature for `norm2'
             Inferred type: norm2 :: forall a. (Floating a) => a -> a -> a
...

rt.hs:2:15:
    Warning: Defaulting the following constraint(s) to type `Double'
             `Floating a' arising from a use of `norm2' at rt.hs:2:15-23
    In the second argument of `($)', namely `norm2 1 1'
    In the expression: print $ norm2 1 1
    In the definition of `main': main = print $ norm2 1 1
stripe x = fromIntegral . round $ x - (fromIntegral (floor x))
main = mapM_ (print . stripe) [0,0.1..2.0]
rt2.hs:1:11:
    Warning: Defaulting the following constraint(s) to type `Integer'
             `Integral b' arising from a use of `fromIntegral' at rt2.hs:1:11-22
    In the first argument of `(.)', namely `fromIntegral'
    In the first argument of `($)', namely `fromIntegral . round'
    In the expression:
            fromIntegral . round $ x - (fromIntegral (floor x))