3

I'm playing codewars to sharpen my Haskell skills, and running into a problem that I haven't had in imperative languages.

Let's say I'm writing a function foo() in javascript, which takes an int, adds two, squares it, subtracts one, and returns the square root of that number.

var foo = function(n) {
  n += 2;
  n = n * n;
  n -= 1;
  n = Math.sqrt(n);
}

I want to check on the state of the data being processed in the function at various points to help me troubleshoot/revise/debug code, so I will insert console.log() statements whenever I want to see where I'm at. For example, am I, in fact, squaring the sum of n+2 correctly halfway through the function? Let's see...

var foo = function(n) {
  n += 2;
  n = n * n;
  console.log("n = " + n);
  n -= 1;
  n = Math.sqrt(n);
}

While this example should be simple enough for a Haskeller to write in one line, if you have a complex function and want to check the state at different points, how do Haskellers do it? Is there a standard practice using the IO() monad? Do they get around it some other way?

duplode
  • 33,731
  • 7
  • 79
  • 150
Mark Karavan
  • 2,654
  • 1
  • 18
  • 38

1 Answers1

6

GHCi has a fancy debugger that lets you step through your code and evaluate it line by line, checking it's state and intermediary results.

But, of course, there is also the printf-style debugging that you are asking for, using the trace function from Debug.Trace. Nothing wrong with using that for small scripts imho, but it's generally discouraged.

trace has the type String -> a -> a, so you pass a string that gets printed (via unsafePerformIO) and any argument that gets simply returned.


In your example we could use it as follows. This is your function translated to Haskell:

foo x = sqrt $ (x+2)**2 - 1

Now we can just add trace and the string we want to see, e.g. "Debug Me: " ++ (show ((x+2)**2)). First import Debug.Trace, though:

import Debug.Trace
foo x = sqrt $ (trace ("Debug Me: " ++ (show ((x+2)**2))) ((x+2)**2)) - 1

A bit ugly? Following David Young's comment below, we better use traceShowId :: Show a => a -> a, if what we want to output is identical to the intermediary result (converted to String, of course):

import Debug.Trace
foo x = sqrt $ (traceShowId ((x+2)**2)) - 1 

See here for a summary of debugging options.

lodrik
  • 472
  • 4
  • 8