I am trying to get a Haskell function to show 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 demonstrate why one version of isPrime is more efficient than another.)
When I load the above code into GHCi, I get the error:
Couldn't match expected type
Bool
with actual typem0 b0
I'm sure this is a n00b mistake. Could someone tell me the right way to accomplish what I'm trying to do?
The problem is, that Haskell has a strict distinction between pure functions such as (+)
and map
and impure actions such as putStrLn
and main
. A pure function is supposed to always yield the same result when given the same input and not modifying anything. This obviously prohibits uses of PutStr
and friends. The type system actually enforces this separation. Each function that does IO or is impure in any way has an IO
sticking in front of it's type.
tl;dr; use trace
from the module Debug.Trace
:
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 beware that the results may be rather surprising as there is no guarantee that your code will actually run; the argument of trace may run once or twice or any other number of times.
Whenever you have these kinds of type errors like Couldn't match expected type X with actual type Y
you should use the haskell type system to guide you.
So let's see what is the problem:
You have a pure function with the type Int -> Bool
. And you want to print some debug output which is clearly not pure (i.e. which lives in the IO Monad).
But anyway what you want to write is s.th. along those lines:
foo x
| x > 0 = debug "ok" True
| otherwise = debug "ohhh...no" False
Still, the type of your function should be foo :: Int -> Bool
So let's define a debug
function that will satisfy the type-checker. It would have to take a String (your debug message) and a Bool (your result) and only evaluate to the Bool.
debug :: String -> Bool -> Bool
debug = undefined
But if we try to implement it, it kind of does not work since we can't escape the IO Monad since the type of putStrLn is putStrLn :: String -> IO ()
. In order to combine it with evaluating to a Bool
we will have to put the Bool
in the context of the IO
too:
debugIO msg result = putStrLn msg >> return result
Ok, let's ask ghci for the type of this function:
Main> :t debugIO
debugIO :: String -> b -> IO b
So we get an IO Bool
but would need just a Bool
.
Is there a function with the type IO b -> b
? A quick lookup on hoogle gives us a hint:
The infamous unsafePerformIO :: IO a -> a
has the type we need here.
So now we could implement our debug
function in terms of debugIO
:
debug :: String -> Bool -> Bool
debug s r = unsafePerformIO $ debugIO s r
which actually is pretty much what you get with the trace
function in the Debug.Trace
package as already pointed out by FUZxxl.
And since we agree that one should never use unsafePerformIO
the usage of the trace
function is preferred. Just keep in mind that despite it's pure type signature it actually is also not referential transparent and uses unsafePerformIO
underneath.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With