web-dev-qa-db-ja.com

Haskellコードをデバッグする方法は?

私は問題があります。私は大きなHaskellプログラムを書きましたが、それは常に小さな入力で動作します。これで、テストしてより大きな入力を生成したい場合、常に次のメッセージが表示されます。

HsProg: Prelude.head: empty list

私が使う Prelude.head 何度も。それが発生するコード行を取得するために、より多くのことを見つけたり、より良いエラー出力を取得したりするにはどうすればよいですか?

41

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ユーザーズガイド を参照してください。

73
hammar

Haskell Wiki --Debugging を見てみてください。これには、問題に対する多くの有用なアプローチが含まれています。

1つの有望なツールは LocH です。これは、empty listエラーをトリガーしたコード内のhead呼び出しを見つけるのに役立ちます。

個人的に、私は safe パッケージをお勧めします。これにより、Preludeのほとんどのpartial関数に注釈を付けることができます(したがって、これらの部分関数のより意識的な使用につながります) )またはさらに良いことに、常に結果を返すheadなどの関数のtotalバリアントを使用します(入力値が定義されている場合) 少なくとも)。

9
hvr

GHC 8以降、詳細なGHC.Stackモジュールまたはいくつかのプロファイリングコンパイラフラグを使用できます Simonのブログ

0
Janus Troelsen