25

でGHC警告を有効にすることは良い習慣と考えられています-Wall. ただし、これらの警告を修正すると、一部の種類のコード構造に悪影響があることがわかりました。

例 1:

フォームf >>を明示的に使用しない場合、同等の do 表記法を使用すると警告が生成されます。_ <- f

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、結局そのまま使用する必要がありますか?

4

6 に答える 6

25

例 1:

Applicative スタイルでパーサーを書くことを再学習しました。パーサーははるかに簡潔です。たとえば、次の代わりに:

funCallExpr :: Parser AST
funCallExpr = do
    func <- atom
    token "("
    arg <- expr
    token ")"
    return $ FunCall func arg

代わりに次のように書きます。

funCallExpr :: Parser AST
funCallExpr = FunCall <$> atom <* token "(" <*> expr <* token ")"

しかし、警告が気に入らない場合は、警告が示すように無効にしてください。

例 2:

ええ、その警告も少しイライラします。しかし、それは私を数回救いました。

それは命名規則に結びついています。私はモジュールをかなり小さく保ち、ほとんどのインポートを修飾したままにするのが好きです (Control.Applicativeおよびのような「表記法」インポートを除くControl.Arrow)。これにより、名前が競合する可能性が低くなり、作業が簡単になります。 hothasktagsタグを使用している場合、このスタイルを許容できるようにします。

同じ名前のフィールドでパターン マッチングを行うだけの場合は、-XNamedFieldPunsまたは-XRecordWildCardsを使用して名前を再利用できます。

data Foo = Foo { baz :: Int, bar :: String }

-- RecordWildCards
doubleBaz :: Foo -> Int
doubleBaz (Foo {..}) = baz*baz

-- NamedFieldPuns
reverseBar :: Foo -> String
reverseBar (Foo {bar}) = reverse bar

もう 1 つの一般的な規則は、レコード ラベルにハンガリー語のプレフィックスを追加することです。

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

しかし、そうです、Haskell でレコードを扱うのは楽しくありません。とにかく、モジュールを小さくし、抽象化をタイトに保てば、これは問題になりません。simpleyyy, manという警告と考えてください。

于 2010-11-14T07:17:49.833 に答える
10

-Wallを使用すると、コードが読みにくくなる可能性があると思います。特に、それがいくつかの算術をしている場合。

他のいくつかの例では、の使用が-Wall読みやすさの悪い変更を示唆しています。

(^)-Wall指数の型署名が必要です

このコードを考えてみましょう:

norm2 x y = sqrt (x^2 + y^2)
main = print $ norm2 1 1

これにより-Wall、次のような2つの警告が表示されます。

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)はいいことではありません。

すべてのトップレベルに型署名が必要です

速くて汚いコードを書くとき、それは迷惑です。最大で1つまたは2つのデータ型が使用されている単純なコードの場合(たとえば、私はDoublesでのみ作業することを知っています)、どこにでも型署名を書き込むと、読み取りが複雑になる可能性があります。上記の例では、型アノテーションがないことを示す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

気を散らすものとして、それらの1つは、型署名が必要な行とは異なる行を指します。

中間計算用の型注釈Integralが必要です

これは最初の問題の一般的なケースです。例を考えてみましょう。

stripe x = fromIntegral . round $ x - (fromIntegral (floor x))
main = mapM_ (print . stripe) [0,0.1..2.0]

それはたくさんの警告を与えます。どこにでもfromIntegral変換して戻す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))

そして、誰もがfromIntegralHaskellでどれくらいの頻度で必要かを知っています...


このような数値コードは、-Wall要件を満たすためだけに判読できなくなるリスクがあります。しかし、私はまだ-Wall確認したいコードを使用しています。

于 2010-11-15T12:12:05.367 に答える
7

デフォルトのオプションとして「-Wall」を引き続き使用し、関連ファイルの先頭にある OPTIONS_GHC プラグマを使用して、ローカルでモジュールごとに必要なチェックを無効にすることをお勧めします。

私が例外を作るかもしれないのは確かに「-fno-warn-unused-do-bind」ですが、1つの提案は明示的な「void」関数を使用することかもしれません...「void f」と書くことは「_ <」よりも良いようです-f'.

名前のシャドーイングについては、できれば避けるのが一般的に良いと思いますが、コードの途中で 'map' を見ると、ほとんどの Haskeller は標準ライブラリ fn を期待するようになります。

于 2010-11-14T07:22:10.813 に答える
6

名前のシャドーイングは非常に危険です。特に、名前がどのスコープで導入されるかを判断するのが難しくなる可能性があります。

do 記法で未使用のパターン バインドはそれほど悪くはありませんが、必要以上に効率の悪い関数が使用されていることを示している可能性があります (たとえばmapM、 の代わりにmapM_)。

BenMos が指摘したように、voidorignoreを使用して未使用の値を明示的に破棄することは、物事を明確にする良い方法です。

一度にすべての警告を無効にするのではなく、コードの一部の警告を無効にできると非常に便利です。また、cabal フラグとコマンド ライン ghc フラグはファイル内のフラグよりも優先されるため、デフォルトで -Wall をどこにでも置くことはできず、1 つのファイル全体に対して簡単に無効にすることさえできません。

于 2010-11-14T19:41:39.330 に答える
4

-Wほとんどが一般的なコーディング スタイル (未使用のインポート、未使用の変数、不完全なパターン マッチなど) に関連する合理的な警告のセットを有効にする、より控えめなオプションもあります。

特に、あなたが言及した2つの警告は含まれていません。

于 2012-03-04T05:33:41.060 に答える
4

これらの警告はすべて間違いを防ぐのに役立ち、抑圧するのではなく尊重する必要があります。Prelude からの名前で関数を定義したい場合は、次を使用して非表示にすることができます

import Prelude 非表示 (マップ)

「非表示」構文は、Prelude と同じパッケージのモジュールにのみ使用する必要があります。そうしないと、インポートされたモジュールの API の変更によってコードが破損する危険があります。

参照: http://www.haskell.org/haskellwiki/Import_modules_properly

于 2010-11-21T17:42:26.897 に答える