A library for debugging Haskell programs. To use, take the functions that you are interested in debugging, e.g.:
module QuickSort(quicksort) where
import Data.List
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (x:xs) = quicksort lt ++ [x] ++ quicksort gt
where (lt, gt) = partition (<= x) xs
Turn on the TemplateHaskell
, ViewPatterns
and PartialTypeSignatures
extensions, import Debug
, indent your code and place it under a call to debug
, e.g.:
{-# LANGUAGE TemplateHaskell, ViewPatterns, PartialTypeSignatures #-}
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
module QuickSort(quicksort) where
import Data.List
import Debug
debug [d|
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (x:xs) = quicksort lt ++ [x] ++ quicksort gt
where (lt, gt) = partition (<= x) xs
|]
We can now run our debugger with:
$ ghci QuickSort.hs
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
[1 of 1] Compiling QuickSort ( QuickSort.hs, interpreted )
Ok, 1 module loaded.
*QuickSort> quicksort "haskell"
"aehklls"
*QuickSort> debugView
The call to debugView
starts a web browser to view the recorded information, looking something like:
You can look and play with the example results for various examples:
quicksort "haskell"
as above.quicksortBy (<) "haskell"
, like quicksort
but using a comparison function and including a trace of partition
itself.lcm_gcd 6 15
, computing lcm 6 15 ^^ gcd 6 15
.debug-pp
debug-pp
is a Haskell source preprocessor for streamlining the debug
instrumentation of a module or a package. It performs the steps described above automatically. That is:
Debug
module,debug
splice using a TH declaration quasiquote, andTo instrument a module, add the following pragma to the top of the file:
{-# OPTIONS -F -pgmF debug-pp #-}
To instrument an entire program, add the following line to your stack descriptor, or if you don't use stack, to your cabal descriptor:
ghc-options: -F -pgmF debug-pp
In both cases you will also need to modify your Cabal descriptor in order to
debug
packagedebug-pp
(required Cabal 2.0) :Library
...
build-tool-depends: debug-pp:debug-pp
debug-pp
tries to find a config file in the following locations (from higher to lower precedence):
.debug-pp.yaml
in the current directory (useful for per-directory.debug-pp.yaml
in the nearest ancestor directory (useful fordebug-pp/config.yaml
in the platform’s configuration directory~/.config
andXDG_CONFIG_HOME
environment variable;.debug-pp.yaml
in your home directory (useful for user-wideUse debug-pp --defaults > .debug-pp.yaml
to dump a
well-documented default configuration to a file, this way you can get started
quickly.
The configuration options include:
main
function with debugRun
.Hoed
backend, whether to enable the automatic deriving of Generic
and Observable
instances.This package offers two alternative backends for generating the debug trace:
import Debug
This is the default backend, which relies on Show
instances to observe values strictly. If your program relies on laziness, it will probably crash or loop.
import Debug.Hoed
A new experimental backend built on top of Hoed. Requires GHC 8.2 or higher
Fully lazy, able to observe function values and provide call stacks: example. The instrumentation is simpler, so it is known to work in more cases. It relies on Observable
instances which are derivable (the TH wrapper can take care of this automatically). Note that it will probably not work in multi threaded environments yet.
Show
(or Observable
) instances, otherwise they will fall back to the default <?>
.The function can be called multiple times with different parameters, and the results of each individual run can be selected inside the UI.
debug [d|...]
blocks inside a module and you can also put more than one function inside a single block.A function being debugged can refer to another function also being debugged, but due to a limitation of Template Haskell, the definition of the function being called must occur above the point of its reference in the source module.
Due to constant applicative forms (CAFs) distorting the debug trace, it is not advisable to run the debugger twice in the same GHCi session.
This tool is quite new, so it has both limitations, places it is incomplete and bugs. Please report all the issues you find and help us make it better.
For practical alternatives for debugging Haskell programs you may wish to consider:
Compared to the above, debug
stresses simplicity of integration and user experience.
debugView
fails talking about Wine?A: If you get wine: invalid directory "/home/f/.wine" in WINEPREFIX: not an absolute path
when running debugView
that means xdg-open
is handled by Wine. Fix that and it will work once more.
debugView
fails with "error: Variable not in scope: debugView"?A: Explicitly load the Debug module in GHCi via :m + Debug