Search code examples
haskellio

putStrLn IO() error when trying to display a list


I was playing around with making custom list displays. The concept is really simple but I keep getting an IO() error. My code is:

displayList :: [Int] -> IO()
displayList [] = putStrLn ""
displayList (firstUnit:theRest) =  putStrLn (show firstUnit ++ "\n" ++ 
                                   displayList theRest)

The error code I am getting is:

• Couldn't match expected type ‘[Char]’ with actual type ‘IO ()’
• In the second argument of ‘(++)’, namely ‘(displayList theRest)’
  In the first argument of ‘putStrLn’, namely
    ‘((show firstUnit) ++ (displayList theRest))’
  In the expression:
    putStrLn ((show firstUnit) ++ (displayList theRest))

The specific part of the line that is getting the error is the displayList theRest not the putStrLn ((show firstUnit) ++ part.

I think I understand what is happening which is that when displayList theRest is called in the line with the error it has the potential eventually after a few recursive calls to return an IO() type from the line displayList [] = putStrLn "" which is not supported as input in the putStrLn function. Would anyone know a way to solve this?


Solution

  • The Problem

    The problem with your code is fairly obvious: as the compiler tells you, you're trying to concatenate a string (((show firstUnit) ++) with an IO() (the return type of your function)

    Solution

    The solution can take two paths: either you want a function that returns the whole string, and then prints it all in one, or just print it step by step recursively. What I mean is:

    Return a string

    displayList :: [Int] -> IO()
    displayList = putStrLn . helper
      where
        helper :: [Int] -> String
        helper [] = ""
        helper (n:ns) = show n ++ "\n" ++ helper ns
    

    This approach works fine, but I believe it's not tidy nor clear.

    Better version

    displayList' :: [Int] -> IO()
    displayList' [] = putStrLn ""
    displayList' (n:ns) =  putStrLn (show n) >> displayList' ns
    

    I think you can see how this version is easier to read. Also note that print :: Show a => a -> IO() works exactly as putStrLn . show