https://wiki.haskell.org/api.php?action=feedcontributions&user=Saminiir&feedformat=atomHaskellWiki - User contributions [en]2024-03-29T08:27:45ZUser contributionsMediaWiki 1.35.5https://wiki.haskell.org/index.php?title=Debugging&diff=58225Debugging2014-05-29T08:49:19Z<p>Saminiir: /* Dynamic breakpoints in GHCi */ The :break command input options have changed, no 'add' option anymore</p>
<hr />
<div>== Stack trace ==<br />
<br />
<br />
<br />
=== General usage ===<br />
<br />
Recent versions of GHC allow a dump of a stack trace (of all cost centres) when an exception is raised. In order to enable this, compile with <code>-prof</code>, and run with <code>+RTS -xc</code>. (Since only the cost centre stack will be printed, you may want to add <code>-auto-all -caf-all</code> to the compilation step to include all definitions in the trace.)<br />
<br />
A more detailed list of options can be found [http://www.haskell.org/ghc/docs/latest/html/users_guide/runtime-control.html#rts-options-debugging in the RTS section] of the GHC user's guide.<br />
<br />
<br />
<br />
=== Example ===<br />
<br />
<haskell><br />
-- test.hs<br />
crash = sum [1,2,3,undefined,5,6,7,8]<br />
main = print crash<br />
</haskell><br />
<br />
<br />
> ghc-7.6.3 test.hs -prof -auto-all -caf-all && ./test +RTS -xc<br />
*** Exception (reporting due to +RTS -xc): (THUNK_2_0), stack trace: <br />
GHC.Err.CAF<br />
--> evaluated by: Main.crash,<br />
called from Main.CAF:crash_reH<br />
test: Prelude.undefined<br />
<br />
== Printf and friends ==<br />
<br />
The simplest approach is to use <tt>Debug.Trace.trace</tt>:<br />
<pre><br />
trace :: String -> a -> a<br />
</pre><br />
: "''When called, trace outputs the string in its first argument, before returning the second argument as its result.'"<br />
<br />
A common idiom to trace a function is:<br />
<pre><br />
myfun a b | trace ("myfun " ++ show a ++ " " ++ show b) False = undefined<br />
myfun a b = ...<br />
</pre><br />
The advantage is that disabling and enabling the trace takes only one line comment.<br />
<br />
You must keep in mind that due to lazy evaluation your traces will only print if the value they wrap is ever demanded.<br />
<br />
The trace function is located in the base package. The package [http://hackage.haskell.org/package/htrace htrace] defines a trace function similar to the one in the base package, but with indentation for better visual effect (see the [http://www.haskell.org/pipermail/haskell-cafe/2012-January/098847.html mailing list thread] for examples). Other tools can be found at [http://hackage.haskell.org/packages/archive/pkg-list.html#cat:debug the debug category in Hackage].<br />
<br />
A more powerful alternative for this approach is [http://hackage.haskell.org/package/hood Hood]. Even if it hasn't been<br />
updated in some time, Hood works perfectly with the current ghc<br />
distribution. Even more, Hugs has it already integrated, see the [http://cvs.haskell.org/Hugs/pages/users_guide/observe.html manual page]. Add an <tt>import Observe</tt> and start inserting observations in your code.<br />
For instance:<br />
<pre><br />
import Hugs.Observe<br />
<br />
f' = observe "Informative name for f" f <br />
f x = if odd x then x*2 else 0<br />
</pre><br />
And then in hugs:<br />
<pre><br />
Main> map f' [1..5]<br />
[2,0,6,0,10]<br />
<br />
>>>>>>> Observations <<<<<<<br />
<br />
Informative name for f<br />
{ \ 5 -> 10<br />
, \ 4 -> 0<br />
, \ 3 -> 6<br />
, \ 2 -> 0<br />
, \ 1 -> 2<br />
}<br />
<br />
</pre><br />
<br />
outputs a report of all the invocations of f and their result.<br />
<br />
I have a handy bogus Hugs.Observe module with no-ops for the observations so that I don't need to remove them manually, expecting that the compiler will optimize them away.<br />
<br />
The [http://hackage.haskell.org/package/GHood GHood] package adds a graphical back-end to Hood. See also the [http://community.haskell.org/~claus/GHood/ GHood homepage].<br />
<br />
<br />
== The Safe Library ==<br />
<br />
There is a safe library of functions from the Prelude that can crash, see [http://community.haskell.org/~ndm/safe/ the safe library]. If you get an error message such as "pattern match failure, head []", you can then use <tt>headNote "extra information"</tt> to get a more detailed error message for that particular call to <tt>head</tt>. The safe library also has functions that return default values and wrap their computation in <tt>Maybe</tt> as required.<br />
<br />
<br />
== Offline analysis of traces ==<br />
The most advanced debugging tools are based in offline analysis of traces. [http://projects.haskell.org/hat/ Hat] is probably the most up-to-date tool for this, offering a comprehensive set of tools. [[User:NeilMitchell|Neil Mitchell]] has made available a Windows port of Hat at [http://projects.haskell.org/~ndm/hat/ his site].<br />
<br />
The disadvantage of these tools is that they are not always compatible with the latest libraries, so you can put them to use only in some cases. <br />
<br />
''Some Hat user should complete this section''<br />
<br />
== Dynamic breakpoints in GHCi ==<br />
<br />
Finally, the [[GHC/GHCi debugger| GHCi debugger]] enables dynamic<br />
breakpoints and intermediate values observation. <br />
<br />
This tool allows to set breakpoints in your code, directly from the GHCi command prompt. An example session:<br />
<pre><br />
*main:Main> :break Main 2<br />
Breakpoint set at (2,15)<br />
*main:Main> qsort [10,9..1]<br />
Local bindings in scope:<br />
x :: a, xs :: [a], left :: [a], right :: [a]<br />
<br />
qsort2.hs:2:15-46> :sprint x<br />
x = _<br />
qsort2.hs:2:15-46> x<br />
</pre><br />
This is an untyped, unevaluated computation. You can use <hask>seq</hask> to force its evaluation and then <code>:print</code> to recover its type<br />
<pre><br />
qsort2.hs:2:15-46> seq x ()<br />
() <br />
qsort2.hs:2:15-46> :p x<br />
x - 10<br />
</pre><br />
<br />
Once a breakpoint is hit, you can explore the bindings in scope, as well as to evaluate any Haskell expression, as you would do in a normal GHCi prompt. The <code>:print</code> command can be very useful to explore the laziness of your code.<br />
<br />
== Source-located errors ==<br />
<br />
[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/loch LocH] provides wrappers over<br />
<hask>assert</hask> for generating source-located exceptions and errors.<br />
<br />
Consider the use of a located <hask>fromJust</hask>:<br />
<br />
<haskell><br />
import Debug.Trace.Location<br />
import qualified Data.Map as M<br />
import Data.Maybe<br />
<br />
main = do print f<br />
<br />
f = let m = M.fromList<br />
[(1,"1")<br />
,(2,"2")<br />
,(3,"3")]<br />
s = M.lookup 4 m<br />
in fromJustSafe assert s<br />
<br />
fromJustSafe a s = check a (fromJust s)<br />
</haskell><br />
<br />
This will result in:<br />
<br />
<haskell><br />
$ ./a.out<br />
a.out: A.hs:12:20-25: Maybe.fromJust: Nothing<br />
</haskell><br />
<br />
This can be automated, using the 'loch' preprocessor, so a program<br />
failing with:<br />
<br />
<code><br />
$ ghc A.hs --make -no-recomp<br />
[1 of 1] Compiling Main ( A.hs, A.o )<br />
Linking A ...<br />
<br />
$ ./A<br />
A: Maybe.fromJust: Nothing<br />
</code><br />
<br />
Can be transformed to a src-located one by adding:<br />
<br />
<haskell><br />
import Debug.Trace.Location<br />
</haskell><br />
<br />
and then recompiling with the preprocessor on:<br />
<br />
<code><br />
$ ghc A.hs --make -pgmF loch -F -no-recomp<br />
[1 of 1] Compiling Main ( A.hs, A.o )<br />
Linking A ...<br />
<br />
$ ./A<br />
A: A.hs:14:14-19: Maybe.fromJust: Nothing<br />
</code><br />
<br />
<br />
== Other tricks ==<br />
<br />
* If you use GHC, you can get a stack trace in the console when your program fails with an error condition. See the [http://www.haskell.org/ghc/docs/latest/html/users_guide/runtime-control.html#rts-options-debugging description of relevant runtime options].<br />
* Some tips how to use GHCi debugger are also in [http://www.haskell.org/pipermail/glasgow-haskell-users/2009-February/016571.html this message].<br />
<br />
<br />
=== Locating a failure in a library function ===<br />
<br />
The simplest way to provide locating in the source code a mismatch<br />
run-time error in the library functions:<br />
<haskell><br />
head, tail, fromJust<br />
</haskell><br />
<br />
and others is to avoid these functions and to use explicit matching instead.<br />
<br />
For example, consider:<br />
<br />
<haskell><br />
g x = h $ fromJust $ f x,<br />
</haskell><br />
<br />
ghc-6.6 often loses the reference to <hask>g</hask>, <hask>f</hask>,<br />
and <hask>h</hask> in its run-time error report, when <hask>f</hask><br />
returns <hask>Nothing</hask>.<br />
<br />
But for the program:<br />
<br />
<haskell><br />
g x = let Just y = f x in h y,<br />
</haskell><br />
<br />
GHC reports:<br />
<br />
<haskell><br />
Main: M1.hs:9:11-22:<br />
Irrefutable pattern failed for pattern Data.Maybe.Just y<br />
</haskell><br />
<br />
Indicating the source of the failure.<br />
<br />
<br />
=== Mysterious parse errors ===<br />
<br />
GHC provides `-ferror-spans`, which will give you the exactly position<br />
of the start and end of an offending statement.<br />
<br />
<br />
=== Infinite loops ===<br />
On glasgow-haskell-users on 21 Nov 2007, pepe made the following suggestion for detecting the cause infinite loops in GHCi. Assuming the offending function is named `loop`, and takes one argument:<br />
<br />
# enable the flag -fbreak-on-error (`:set -fbreak-on-error` in GHCi)<br />
# run your expression with :trace (`:trace loop 'a'`)<br />
# hit Ctrl-C while your program is stuck in the loop to have the debugger break in the loop<br />
# use :history and :back to find out where the loop is located and why.<br />
<br />
''(For which versions? ghci >= 6.8?)''<br />
<br />
[[Category:Tools]]<br />
[[Category:Development tools]]</div>Saminiir