10.2. あなたのプログラムが「正しくないこと」をしたとき

(遅すぎる、あるいはメモリを食いすぎるHaskellプログラムについては、第6章. より早く、より高速で、より小さく、より慎ましくあるための助言を見てほしい)

“助けて!プログラムがクラッシュした!”

(つまり、「セグメンテーション違反」や「core dumped」)

プログラムで他言語呼び出しを行っておらず、安全でないと分かっている関数(unsafePerformIOなど)も使っていないなら、一つの例外をのぞいて、これは常にGHCシステムのバグである。例外とは、プログラムが複数のモジュールから成り立っているとき、それぞれのモジュールは、そのモジュールが依存しているモジュールが全てコンパイルされた後でコンパイルされなければならない(.hi-bootを使う場合を除く。この場合それらはモジュールのソースと正しく対応していなければならない)、という条件に反した場合である。

例えば、インポートされる値の型について、インタフェースファイルに誤った情報がある場合、インポート元モジュールの生成コードが壊れることになる。これは、インタフェース中のプラグマにも適用される。プラグマに誤った情報(例えば値の項数について)がある場合、壊れたコードが得られる。さらに、型が変わらなくても項数が変わることがあり得る。

簡単に言うと、モジュールをコンパイルした後にそのインタフェースが変わったら、そのインタフェースをインポートするモジュールは全て再コンパイルしなければならない

インタフェースが変わったときに知らせてくれる便利なオプションとして-hi-diffsがある。これは、変更のあったインタフェースファイルにdiffを施すものである。

makeを使っているなら、依存性情報を自動的に生成して、全てのモジュールが、インポート先インタフェースに対して、古くならないようにすることができる。4.7.11. 依存関係を生成するを参照してほしい。

「バグ報告の前の最後のコンパイル」をすることになったら、コンパイルオプションに-dcore-lintを追加する(より詳しい検査ができる)ことを推奨する。

つまり、core dumpするとしてバグを報告する前に、次のようなことをするべきだろう。

% rm *.o        # オブジェクトファイルを片付ける
% make my_prog  # プログラムを再makeする。変更点をはっきりさせるには-hi-diffsを使う。
                # 上述のように、より偏執的に-dcore-lintを使うこともできる。
% ./my_prog ... # もう一回...

もちろん、プログラム中に他言語関数の呼び出しがあるなら、話は全く別である。ヒープを破壊したり、スタックを破壊したり、なんでもできるからである。

“プログラムが「absent」なargumentにenterした”

これは間違いなくGHCのバグが原因である。報告してほしい。(1.3. GHCのバグを報告するを見よ)

“「arithmetic(または「floating」) exception」って何?”

IntFloatDoubleの四則演算は検査されない。オーバーフロー、アンダーフロー、精度の損失は、黙って見過ごされるか、OSによって例外として報告される(どちらかはシステムによる)。零による除算の結果、受け取られない例外が発生するかもしれない。(もしそうなったら報告してほしい)