Thankfully, there's a number of solutions.
The GHCi debugger provides a way of inspecting code.
:b Nsets a break point in the loaded module at a specific line. Taking the anagrams example I set
anagrams <-anagramList wordfile.
anagramsOf :: String -> IO ()
anagramsOf word = do
anagrams <- anagramList wordfile
putStrLn (show (Map.lookup (stringToKey word) anagrams))
When the program is run and the breakpoint is hit we get the following:
Stopped at anagrams.hs:31:2-57
_result :: IO () = _
anagrams :: Map String (Set String) = _
word :: String = _
[anagrams.hs:31:2-57] *Main> :list
30 anagrams <- anagramList wordfile
31 putStrLn (show (Map.lookup (stringToKey word) anagrams))
:listis used to list of the free variables in scope (
word) and these are available to inspect in the debugger.
_resultis a binding for the result expression. Once you've hit a breakpoint, you can use use
:traceto continue to the next breakpoint, recording the history as you go along.
:forwardallow you to go up and down the list of evaluated expressions and inspect each one.
The Haskell Wiki has a section devoted to debugging which brought me to the Debug.Trace module. This allows you to print some text and return the evaluation of the next expression e.g.
Debug.Trace.trace "1+1=" (1 + 1).
Initially, I couldn't understand how the type of
String -> a -> a, but then I found
System.IO.Unsafe. It comes with a large health warning that it doesn't enforce ordering on IO and it's type unsafe. Evil, yet useful (at least to write the trace functions).