Haskell – Error trying to call putStrLn in function

debugginghaskell

I'm trying to put a 'print out' function call in a Haskell function.

(a simple debug message).

Below is my code and error message from the compiler (GHC 6.10).

I don't quite understand why it is lumping the putStr call and the empty array.

The empty array is the return value for that particular case (the print out message is actually just a stub for now).

Any idea why this is isn't working?

My Code:

isAFactor :: Integer -> Integer -> Bool 
isAFactor x y = x `mod` y == 0

findFactors :: Integer -> Integer -> [Integer]
findFactors counter num = 
    let quotient = div num 2
    in
        if(counter >  quotient)
            then do
                putStrLn ("factorList is  : " ++ show quotient)  (*** Line 10***)
                []
        else if(isAFactor num counter)
            then [counter] ++ [quotient] ++ findFactors (counter + 1) num
        else
            findFactors (counter + 1) num

Error from ghc

    test.hs:10:4:
    Couldn't match expected type `[a] -> [Integer]'
           against inferred type `IO ()'
    In the expression:
        putStrLn ("factorList is  : " ++ show quotient) []
    In the expression:
        do putStrLn ("factorList is  : " ++ show quotient) []
    In the expression:
        if (counter > quotient) then
            do putStrLn ("factorList is  : " ++ show quotient) []
        else
            if (isAFactor num counter) then
                  [counter] ++ [quotient] ++ findFactors (counter + 1) num
            else
                findFactors (counter + 1) num

Best Answer

It is important to remember that Haskell is a pure functional language. This means that functions are not allowed to have any side effects at all, including printing debug messages to your screen.

It is however possible to break this purity and it can be useful in debugging. Take a look at the module Debug.Trace. There you will find a function trace :: String -> a -> a. You can use it in your code like this:

import Debug.Trace

isAFactor :: Integer -> Integer -> Bool 
isAFactor x y = x `mod` y == 0

findFactors :: Integer -> Integer -> [Integer]
findFactors counter num = 
    let quotient = div num 2
    in
        if(counter >  quotient)
                then trace ("factorList is: " ++ show quotient) [] 
        else if(isAFactor num counter)
            then [counter] ++ [quotient] ++ findFactors (counter + 1) num
        else
            findFactors (counter + 1) num

As the comments suggested:

Haskell is also a lazy language. An Expression is not evaluated before the result is actually needed. Using the trace function can be a bit confusing in a lazy setting because it is not always easy to understand when the trace message is printed to screen (if it is printed at all).

As haskell is a very different kind of language it is perhaps best to try and develop programs in a equally different way. Try to reason about your functions instead of using trace and similar "unpure" constructs. Learn to take advantage of haskells powerful type system and use (for example) QuickCheck to test your function once it passed the type checker.

Related Topic