私は問題があります。私は大きなHaskellプログラムを書きましたが、それは常に小さな入力で動作します。これで、テストしてより大きな入力を生成したい場合、常に次のメッセージが表示されます。
HsProg: Prelude.head: empty list
私が使う Prelude.head
何度も。それが発生するコード行を取得するために、より多くのことを見つけたり、より良いエラー出力を取得したりするにはどうすればよいですか?
GHCiオプション-fbreak-on-exception
が役立つ場合があります。これがデバッグセッションの例です。まず、ファイルをGHCiにロードします。
$ ghci Broken.hs
GHCi, version 7.0.2: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
[1 of 1] Compiling Main ( Broken.hs, interpreted )
Ok, modules loaded: Main.
次に、-fbreak-on-exceptions
をオンにして、式(この場合はプログラム全体に対してmain
)をトレースします。
*Main> :set -fbreak-on-exception
*Main> :trace main
Stopped at <exception thrown>
_exception :: e = _
例外で停止しました。 :list
を使用してコードを見てみましょう。
[<exception thrown>] *Main> :list
Unable to list source for <exception thrown>
Try :back then :list
例外はPrelude.head
で発生したため、ソースを直接確認することはできません。しかし、GHCiが通知したように、:back
に移動して、トレースの前に何が起こったかをリストすることができます。
[<exception thrown>] *Main> :back
Logged breakpoint at Broken.hs:2:23-42
_result :: [Integer]
[-1: Broken.hs:2:23-42] *Main> :list
1
2 main = print $ head $ filter odd [2, 4, 6]
3
ターミナルでは、問題のある式filter odd [2, 4, 6]
が太字で強調表示されています。したがって、これはこの場合、空のリストに評価された式です。
GHCiデバッガの使用方法の詳細については、 GHCユーザーズガイド を参照してください。
Haskell Wiki --Debugging を見てみてください。これには、問題に対する多くの有用なアプローチが含まれています。
1つの有望なツールは LocH です。これは、empty listエラーをトリガーしたコード内のhead
呼び出しを見つけるのに役立ちます。
個人的に、私は safe パッケージをお勧めします。これにより、Preludeのほとんどのpartial関数に注釈を付けることができます(したがって、これらの部分関数のより意識的な使用につながります) )またはさらに良いことに、常に結果を返すhead
などの関数のtotalバリアントを使用します(入力値が定義されている場合) 少なくとも)。
GHC 8以降、詳細なGHC.Stackモジュールまたはいくつかのプロファイリングコンパイラフラグを使用できます Simonのブログ 。