views:

1384

answers:

4

Basically what I need to do is write a function that takes in a list of type [(String,String)] and print out the contents so that, line-by-line, the output looks like this:

FirstString : SecondString

FirstString : SecondString

..etc, for every item in the list. I've got the following code and it prints it out, but for some reason it prints out a line containing [(),()] at the end.

display :: Table -> IO()
display zs = do {xs <- sequence [putStrLn (a++" = "++b) | (a,b) <- zs]; print xs }

Is there anything I'm doing wrong?

+7  A: 

The final print xs is unnecessary. sequence here is returning a bunch of ()s (the return value of putStrLn), and print is printing that out as well.

While you're at it, now that print xs is gone, you can get rid of the xs variable binding, and make sequence into sequence_ to throw away the return value, giving:

display :: Table -> IO()
display zs = sequence_ [putStrLn (a++" = "++b) | (a,b) <- zs]
bdonlan
If memory is a concern, you may want to check out newacct's method (below).
Tim Stewart
+3  A: 

Write a function that takes a tuple to a string, formatted as you wish.
Then concatMap that function over your list; print the result.

ja
+3  A: 

You could even use mapM:

display :: Table -> IO ()
display = mapM_ (\(a,b) -> putStrLn (a++" = "++b))
newacct
This method uses less memory than bdonlan's method. On my sample data, this method used about 70k less. I wonder if bdonlan's method used more memory because it had to create a list of IO actions.
Tim Stewart
How are you measuring memory use? Haskell creates a /lot/ of ephemeral allocations, so what it probably means is that this is just plain faster :)
bdonlan
+4  A: 

I would agree with ja that you should split up your code in to two functions:

  • A pure part: a function that takes your data structure and turns it into a string
  • An impure part, that renders that string to the console

Here's a simple implementation:

showTable :: Table -> String
showTable xs = concatMap format xs
  where
    format (a, b) = a ++ " : " ++ b ++ "\n"

display :: Table -> IO ()
display table = putStr (showTable table)

This design has two advantages:

For one, most of your `logic' is in the pure part of the code, which is nice, in a functional programming kind of way.

Secondly, and this is just simple software engineering principle; you now have a reusable function that you can use, should you ever want to format your data structure in another part of your code (seems likely).

Tom Lokhorst