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))