4.8. 警告と正気度チェックのためのオプション

GHCでは、いくつかのオプションを使って、生成する致命的でないエラーメッセージ(警告ともいう)の種類を選ぶことができる。デフォルトでは、一般にプログラムのバグを示していることが多い警告が有効になっている。これは-fwarn-overlapping-patterns-fwarn-warnings-deprecations-fdeprecated-flags-fwarn-duplicate-exports-fwarn-missing-fields-fwarn-missing-methods-fwarn-lazy-unlifted-bindings-fwarn-wrong-do-bind-fwarn-unsupported-calling-conventions-fwarn-dodgy-foreign-importsである。以下のフラグは標準的な警告の「詰め合わせ」を簡単に選択するためのものである。

-W:

標準的な警告に加えて、 -fwarn-incomplete-patterns-fwarn-dodgy-exports-fwarn-dodgy-imports-fwarn-unused-matches-fwarn-unused-imports-fwarn-unused-bindsを提供する。

-Wall:

疑わしいコードであることを示し得る全ての警告オプションを有効にする。-Wallで有効にされない警告は、-fwarn-tabs-fwarn-incomplete-uni-patterns-fwarn-incomplete-record-updates-fwarn-monomorphism-restriction-fwarn-auto-orphans-fwarn-implicit-prelude-fwarn-missing-local-sigs-fwarn-missing-import-listsである。

-w:

全ての警告を、標準的なものおよび-Wallが有効にしないものも含めて、無効にする。

-Werror:

全ての警告を致命的なエラーにする。一括コンパイルのときに警告を見逃さないようにするのに便利である。

-Wwarn:

警告を警告として扱い、エラーにしない。これはデフォルトだが、-Werrorフラグを否定するのに便利である。

以下は全ての警告オプションの説明である。なんらかの警告を無効にしたいときは、単に対応する-fno-warn-...をコマンド行から与えれば良い。

-fdefer-type-errors:

可能なかぎり多くの型エラーを実行時まで遅らせる。コンパイル時には(エラーの代わりに)警告が出る。実行時、型エラーに依存した値を使うと、実行時エラーが発生する。しかし、コードのうち型の合っている部分はすべて問題なく走らせることができる。7.13. 型エラーを実行時まで遅らせるを見よ

-fhelpful-errors:

名前やパッケージがスコープにないとき、意図されていたかもしれない名前・パッケージを提案する。

このオプションはデフォルトで有効である。

-fwarn-unrecognised-pragmas:

GHCが認識できないプラグマが使われているときに警告を発する。GHCは、自身が使うプラグマの他に、他のツールが使うことが知られているプラグマも認識する。例えばOPTIONS_HUGSDERIVEといったものである。

このオプションはデフォルトで有効である。

-fwarn-warnings-deprecations:

WARNINGまたはDEPRECATEDプラグマの付いたモジュール・関数・型が使われたときに警告を発する。このプラグマについて詳しくは7.18.4. WARNINGおよびDEPRECATEDプラグマを見よ。

このオプションはデフォルトで有効である。

-fwarn-deprecated-flags:

非推奨のコマンド行フラグが使われたときに警告を発する。

このオプションはデフォルトで有効である。

-fwarn-unsupported-calling-conventions:

対応していない呼び出し規約を使った他言語宣言があると警告を発する。特に、stdcall呼び出し規約がi386以外のアーキテクチャで使われると、ccallとして扱われる。

-fwarn-dodgy-foreign-imports:

次の形式のforeign importに対して警告を発する。

foreign import "f" f :: FunPtr t

なぜなら、これはおそらく次のようになっているべきだからである。

foreign import "&f" f :: FunPtr t

最初の形式は、引数を取らず、「t」型のC関数へのポインタを返す(純粋な)C関数として「f」を宣言する。一方、二番目の形式は「f」自体が「t」型のC関数であると宣言する。前者は通常ミスであり、クラッシュを引き起すためデバッグが難しい。そのためこの警告がある。

-fwarn-dodgy-exports:

データ型Tが全ての構築子を伴って、つまりT(..)としてエクスポートされているが、それが型シノニムにすぎない場合に警告を発する。

また、あるモジュールが再エクスポートされているが、そのモジュールが何もエクスポートしていない場合にも警告する。

-fwarn-dodgy-imports:

データ型Tが全ての構築子を伴ってインポート(つまりT(..))されているものの、抽象的にエクスポート(つまりT)されている場合に警告を出力する。

-fwarn-lazy-unlifted-bindings:

持ち上げられていない型(訳注: unlifed type; ボトムを持たない型)が、まるで遅延するかのように束縛されている場合に警告を発する。例えばwhere (I# x) = ...のような場合である。代わりにwhere !(I# x) = ...を使うこと。GHC 7.2では、これは警告でなくエラーになる予定である。

-fwarn-duplicate-exports:

エクスポートリスト中で重複している要素について警告する。大きなエクスポートリストを管理しているとき、そこから何かを削除したのに相変わらずそれがエクスポートされ続ける、という事態を回避するのに有用である。

このオプションはデフォルトで有効である。

-fwarn-hi-shadowing:

現在のディレクトリにあるモジュールやインタフェースファイルが、ライブラリディレクトリなどにある同名のものを隠しているときに警告する。

-fwarn-identities:

Preludeの数値変換が、型Tを同じ型Tに変換しているときに警告を出力するようにする。このような呼び出しはno-opであり省くことができる。以下の関数が検査される。toIntegertoRationalfromIntegralrealToFrac

-fwarn-implicit-prelude:

Preludeが暗黙にインポートされたときにコンパイラが警告するようにする。これは、Preludeモジュールをimport ... Prelude ...で明示的にイポートしたり、暗黙のインポートが無効にされたりしていない限り発生する。(暗黙のインポートを無効にするには、-XNoImplicitPreludeLANGUAGE NoImplicitPreludeプラグマを使う)

暗黙にPreludeを参照する構文については警告が生成されない。-XNoImplicitPreludeによって、その構文がPreludeを参照するかどうかが変わったとしても同じである。例えば、368Prelude.fromInteger (368::Prelude.Integer)(ここでPreludeは、コンパイル中のモジュールが何をインポートしているかに関わらず、実際のPreludeモジュールを指す)を意味したとしても警告はされない。

この警告はデフォルトで無効である。

-fwarn-incomplete-patterns, -fwarn-incomplete-uni-patterns:

-fwarn-incomplete-patternsは、パターン照合が実行時に失敗する可能性がある場合に警告する。下記の関数gは非空のリストに適用されたときに失敗するので、-fwarn-incomplete-patternsが有効ならコンパイラはこれについて警告を発する。

g [] = 2

このオプションは少々うるさいことがあり、また常にプログラムのバグを示しているわけでもないので、デフォルトでは有効になっていない。しかし、関数を書くときは全ての場合に対応するのが一般には良い習慣とされており、これは-Wによって有効になる。

フラグ-fwarn-incomplete-uni-patternsはこれと似ているが、単一のパターンしか許さない構文要素、つまりラムダ式およびパターン束縛についてのみ適用される。

h = \[] -> 2
Just k = f y

-fwarn-incomplete-record-updates:

下記の関数fBarに適用されたときに失敗する。-fwarn-incomplete-record-updatesが有効だと、このような場合に警告が発せられる。

data Foo = Foo { x :: Int }
         | Bar

f :: Foo -> Foo
f foo = foo { x = 6 }

このオプションはとてもうるさいことがあり、プログラムのバグを示していないことがしばしばあるので、デフォルトでは有効にされていない。

-fwarn-missing-fields:

このオプションはデフォルトで有効であり、ラベル付きフィールドを使った構築が完全でない、つまり一つ以上のフィールドについて初期化子を欠いているときに警告する。これはエラーではないが(省略されたフィールドはボトムで初期化される)、しばしばプログラムの誤りを示している。

-fwarn-missing-import-lists:

qualifiedでないimport宣言で、スコープに導入する実体を明示的に列挙していないものを使った場合に警告する。例を示す。

module M where
  import X( f )
  import Y
  import qualified Z
  p x = f x x

-fwarn-import-listsフラグは、Yのインポートについては警告するが、Xについては警告しない。もしモジュールYが(たとえば)fをエクスポートするように後で変更されたら、Mにおけるfへの参照が曖昧になる。Zのエクスポートを拡張してもMでの曖昧性に繋がる可能性は低いので、Zのインポートについては警告は生成されない。

-fwarn-missing-methods:

このオプションはデフォルトで有効であり、インスタンス宣言が一つ以上のメソッドを欠いていて、しかもそのメソッドのデフォルト定義が対応するクラス宣言にないときに警告する。

この警告はメソッド名がアンダースコアで始まっているときには抑止される。これが便利なのは例えば次のような場合である。

	      class C a where
	        _simpleFn :: a -> String
	        complexFn :: a -> a -> String
	        complexFn x y = ... _simpleFn ...
	      

意図は、(a) クラスの利用者は専らcomplexFnを呼び、_simpleFnを呼ぶことはない。(b) インスタンス宣言ではcomplexFn_simpleFnのどちらかを定義すれば良い。というものである。

-fwarn-missing-signatures:

全てのトップレベルの関数・値に型シグネチャがあることをGHCに確認させたいなら、-fwarn-missing-signaturesオプションを使うと良い。警告の一部としてGHCは推論された型も報告する。これはデフォルトで無効である。

-fwarn-missing-local-sigs:

-fwarn-missing-local-sigsフラグを使うと、GHCはあらゆる多相的な局所束縛について警告する。警告の一部としてGHCは推論された型も報告する。このオプションはデフォルトで無効である。

-fwarn-name-shadowing:

このオプションが有効だと、内側のスコープの値と同名の外側のスコープの値があるとき、つまり内側の値が外側のものを隠すときに警告する。これはミスタイプが原因の発見しがたいバグを捕らえることがある。例えば、f = ... let f = id in ... f ...において、再帰呼び出しであるはずのものが意図せず捕捉されるというものがある。

この警告は、アンダースコアで始まる名前については抑制される。例。

             f x = do { _ignore <- this; _ignore <- that; return (the other) }
          

-fwarn-orphans, -fwarn-auto-orphans:

これらのオプションが有効なら、モジュールに「孤立した」インスタンス宣言や書き換え規則があるときに警告する。インスタンス宣言が孤立インスタンス宣言なのは、クラスおよびインスタンス化される型の両方と別のモジュールに置かれているときである。規則が孤立規則なのは、それが別のモジュールで宣言された関数についての規則であるときである。「孤立した」ものを含むモジュールは孤立モジュールと呼ばれる。

問題は、孤立モジュールについては、そのインスタンスや規則が意味を持つ場合に備えて、他に理由がなくても、GHCが積極的にインタフェースファイルを読まなければいけないということである。詳しくは4.7.12. 孤立モジュールと孤立インスタンス宣言を参照せよ。

-fwarn-orphansフラグは、ユーザによって書かれた孤立規則や孤立インスタンスについて警告する。 -fwarn-auto-orphansフラグは、自動生成された孤立規則、特に型クラス(Specialise)や引数の値(SpecConstr)についての特殊化の結果として生成されたものについて警告する。

-fwarn-overlapping-patterns:

デフォルトで、コンパイラはパターンが重複しているときに警告する。例えば以下のような場合である。

f :: String -> Int
f []     = 0
f (_:xs) = 1
f "2"    = 2

この場合、fの最後のパターン照合には決して到達しない。二番目のパターンがこれに重複しているからである。冗長なパターンはプログラマの誤りであることが、そうでない場合よりも多い。そのため、このオプションはデフォルトで有効である。

-fwarn-tabs:

ソースファイルにタブがあるときにコンパイラが警告するようにする。

この警告はデフォルトで無効である。

-fwarn-type-defaults:

数値型に対するデフォルト化機構が発動したときに警告・通知する。これは、あるデフォルトを前提としたコードを別のデフォルトの下のコードに変換するときに便利である。例えば、1という値に特に制約がないとき、Haskell 1.4の「デフォルトのデフォルト」は型Intを与えるが、Haskell 98以降ではこれはIntegerである。これは実行時性能と挙動に影響を与える可能性があるので、通知されると便利である。

この警告はデフォルトで無効である。

-fwarn-monomorphism-restriction:

Haskellの単相性制限が適用されるソースを書いたときにコンパイラがそれを警告/通知するようにする。単相性制限が黙って適用されると予期せぬ振る舞いの原因になることがあるので、これが適用されたという明示的な警告があると便利なことがある。

この警告はデフォルトで無効である。

-fwarn-unused-binds:

未使用の関数定義(および局所的な束縛)を報告する。トップレベルの関数については、その束縛がエクスポートされていない場合のみ警告される。

ある定義が「使われている」のは、(a)エクスポートされている、または(b)他の使われている関数定義の右辺で言及されている、または(c)定義される関数がアンダースコアで始まっている、ときである。最後の条件のおかげで、未使用の束縛に対する警告を選択的に抑制することができる。

ある変数が他の未使用の束縛の右辺に現れても、その変数は未使用だと報告される点に注意。

-fwarn-unused-imports:

明示的にインポートされながら使われていないモジュールを全て報告する。ただし、import M()の形のインポートは報告されない。これはインスタンス宣言(Haskellでは無名である)をインポートするための有用な決まり文句だからである。

-fwarn-unused-matches:

パターン照合で発生する未使用の変数を全て報告する。これには、単一の変数から成るパターンも含む。例えば、f x y = []に対してはxyが未使用だと報告する。この警告は変数名がアンダースコアからはじまる場合は抑制される。つまり、

	       f _x = True
	    

のような場合である。

-fwarn-unused-do-bind:

doおよびmdoブロックの中の式が、情報を黙って捨てているように見える場合に報告する。例えば、do { mapM popInt xs ; return 10 }の場合、doブロックの最初の文が怪しいと報告される。これの型はStackM [Int]であってStackM ()でなく、この[Int]の値が何にも束縛されていないからである。この警告は、何かを捨てていることをソースコード中で明示的に述べることによって抑制できる。

	       do { _ <- mapM popInt xs ; return 10 }
	    

もちろん、この特定の場合にはもっと良い方法がある。

	       do { mapM_ popInt xs ; return 10 }
	    

-fwarn-wrong-do-bind:

doおよびmdoブロックの中の式が、束縛を欠いているように見える場合に報告する。例えば、do { return (popInt 10) ; return 10 }の場合、doブロックの最初の文が怪しいと報告される。これの型はStackM (StackM Int)(同じモナド構築子が二回適用された形)であるが、その結果を束縛することで「荷解き」がされていない。この警告は、何かを捨てていることをソースコード中で明示的に述べることによって抑制できる。

	       do { _ <- return (popInt 10) ; return 10 }
	    

ほとんど全ての意味のあるプログラムについてこれはバグを示しているはずである。おそらく、意図としては次のように書きたかったのだろう。

	       do { popInt 10 ; return 10 }
	    

本当に偏執的な気分なら、-dcore-lintオプションを使うと良い。これは、GHC内部でのパス内正気度チェックを有効にする。(これがチェックするのはGHCの正気であり、あなたの正気ではない)