How to use putStrLn for tracing (Haskell)

I am trying to get a Haskell function to display whenever it is applied by adding a call to "putStrLn":

isPrime2 1 = False isPrime2 n = do putStrLn n null (filter (==0) (map (mod n) (filter isPrime2 [2..(floor (sqrt(fromIntegral (n-1))))]))) 

(The ultimate goal is to show why one version of isPrime is more effective than another.)

When I load the above code into GHCi, I get an error:

Failed to match expected Bool type with actual type m0 b0

I am sure this is n00b error. Can someone tell me the correct way to accomplish what I'm trying to do?

+4
source share
2 answers

The problem is that Haskell has a strict distinction between pure functions like (+) and map , and unclean actions like putStrLn and main . It is assumed that a pure function always gives the same result when specifying the same input and does not change anything. This explicitly prohibits the use of PutStr and friends. The type system actually provides this separation. Each function that makes IO or is unclean in any way has an IO type in front of it.


TL; dg; use trace from the Debug.Trace module:

 import Debug.Trace isPrime2 1 = False isPrime2 n = show n `trace` null (filter (==0) (map (mod n) (filter isPrime2 [2..(floor (sqrt(fromIntegral (n-1))))]))) 

But be careful that the results can be quite unexpected, since there is no guarantee that your code will actually run; the trace argument can be executed once or twice or any other number of times.

+16
source

Whenever you have these types of errors like Couldn't match expected type X with actual type Y , you should use a system like haskell to guide you.
So let's see what the problem is:

You have a pure function with type Int -> Bool . And you want to print some debug output that is clearly not clean (i.e. Which lives in IO Monad ).
But in any case, what you want to write is s.th. along these lines:

 foo x | x > 0 = debug "ok" True | otherwise = debug "ohhh...no" False 

However, your function type should be foo :: Int -> Bool

So, let's define a debug function that will satisfy type checking. He will have to take the line (your debug message) and Bool (your result) and only evaluate Bool.

 debug :: String -> Bool -> Bool debug = undefined 

But if we try to implement it, this does not work, since we cannot avoid IO Monad, since the type putStrLn is equal to putStrLn :: String -> IO () . To combine it with a grade on Bool , we also need to put Bool in the context of IO :

 debugIO msg result = putStrLn msg >> return result 

Ok, ask ghci about the type of this function:

 Main> :t debugIO debugIO :: String -> b -> IO b 

So, we get IO Bool , but you just need Bool for this.
Is there a function with type IO b -> b ? A quick hoogle search gives us a hint:

The infamous unsafePerformIO :: IO a -> a has the type we need here.
So now we can implement our debug function in terms of debugIO :

 debug :: String -> Bool -> Bool debug sr = unsafePerformIO $ debugIO sr 

which is actually what you get with the trace function in the Debug.Trace package, as FUZxxl already pointed out. <w> And since we agree that you should never use unsafePerformIO , the use of the trace function is preferred. Just keep in mind that in spite of this being a pure type signature, in fact it is also not referential transparent and uses unsafePerformIO under it.

+3
source

All Articles