これまで GHC では、スタックトレースを取ることが有効なデバッグ方法ではなかった。
なぜなら遅延評価では、(再帰であってもなくても)末尾呼び出しは単なるジャンプになるから、スタックを使わないのである。スタックに戻る場所を積むのは、case と of の中で評価される式だけだ。(つまり、ここは正格に評価される。)
この問題を解決するために GHC 7.4.2 から、わざわざスタックにログを残して、スタックトレースが取れるようになった。すなわち、最新の Haskell Platform をインストールしていれば、この機能を使えるということだ。
例として、以下のプログラムを考えよう。
module Main where main :: IO () main = print $ foo 3 + 1 foo :: Int -> Int foo x = x * 2 + bar x bar :: Int -> Int bar x = x + 2 - baz x baz :: Int -> Int baz x = x `div` 0
baz で 0 割り算が起こる。ここで、main -> foo -> bar -> baz というスタックトレースが取れるか実験してみる。
まず、上記のファイルを -prof -fprof-auto-top 付きでコンパイルする。
% ghc main.hs -prof -fprof-auto-top
単に実行すると、こんな感じ。
% ./main main: divide by zero
スタックトレースを取るためには、+RTS -p -xc オプション付きで実行する。
% ./main +RTS -p -xc Exception (reporting due to +RTS -xc): (THUNK_2_0), stack trace: GHC.Err.CAF --> evaluated by: Main.baz, called from Main.bar, called from Main.foo, called from Main.main, called from Main.CAF --> evaluated by: Main.bar, called from Main.foo, called from Main.main, called from Main.CAF --> evaluated by: Main.foo, called from Main.main, called from Main.CAF --> evaluated by: Main.main, called from Main.CAF main: divide by zero
めでたい。
GHCi からは、この機能は使えないようだ。