1

Hi I have small problem with printing [[[Char]]] using IO.

I have a [[[Char]]] list - in another words [[String]]

I would like to print them like

FirstStringOfFirstListOfStrings
SecondStringOfFirstListOfStrings
.
.
.
LastStringOffFirstListofStrings
(some gap anything empty line "----" string anything)
FirstStringOfSecondsListOfStrings

In another words I don't want the [String] to be printed one under another (one row break at least or some line filled with ------ for example)

mapM_ (mapM_ print) 

My idea was to compose the (mapM_ print) function with another but that doesn't seem to work. Any suggestions?

Edit: Here's an example, as requested

data to print: [["abc","cde","efg"],["hjk","mno","prs"],["stu","wxy","zzz"]]

while using mapM_ (mapM_ print) it prints like

abc
cde
efg
hjk
mno
prs
stu
wxy
zzz

But I would like it to be printed like this:

abc
cde
efg

hjk
mno
prs

stu
why
zzz

They can be separated by an empty line or some string.

AndrewC
  • 32,300
  • 7
  • 79
  • 115
user2184057
  • 924
  • 10
  • 27
  • 2
    You could help us by showing example input and output. You should also consider using a pure function to define the final string(s) to output before invoking IO. – Chris Kuklewicz Jun 30 '13 at 10:13
  • as you requested i put an example of code well that [[String]] Board is an result of big nondeterministic algoritm making it pure would be quite hard i think there is a way to do it but monad types restrits me hard – user2184057 Jun 30 '13 at 10:23

3 Answers3

2

With your example the code, for any separator 'sep' is then:

import Data.List (intercalate)

let x = [["abc","cde","efg"],["hjk","mno","prs"],["stu","wxy","zzz"]]

p sep = putStr . unlines . intercalate sep

main = do
    p "" x
    p "---" x
Chris Kuklewicz
  • 8,123
  • 22
  • 33
2

Lets start with types. What you have is [[String]] and what you want is [[IO ()]] i.e each String gets converted to a IO () action (to print it). Lets try to achieve this:

strToPrint :: [[String]] -> [[IO ()]]
strToPrint strs = map (map putStrLn) strs                

Now we want [[IO ()]] to flatten to get [IO ()] where we insert the desired line break print action as well while flattening the list.

flattenActions :: [[IO ()]] -> [IO ()]
flattenActions actions = concat $ intersperse [(putStrLn "")]  actions

Now we can execute these [IO ()] action one by one using sequence_. It seems we can combine all these functions into one function using functional composition and hence we get

printStrings :: [[String]] -> IO ()
printStrings  = sequence_ . flattenActions . strToPrint

And use it like:

main = printStrings [["a","b","c"],["d","e","f"]]

You can then look for making this more generic and refactor it accordingly.

Ankur
  • 33,367
  • 2
  • 46
  • 72
  • Since I'm a nitpicker, I'll point out that `(concat .) . intersperse == intercalate`, except that the latter is (I think) liable to be more efficient. – Ptharien's Flame Jul 05 '13 at 22:36
0

Remember that mapM_ takes a function that returns a monadic action as its parameter. That action can be composed using the normal monadic operations.

So in your code sample you have:

printStrings :: [[String]] -> IO ()
printStrings = mapM_ (mapM_ putStrLn)

Whereas you would like to have:

printStrings :: [[String]] -> IO ()
printStrings = mapM_ (\xs -> (mapM_ putStrLn) xs >> putStrLn ""))

So what we do is to replace the inner mapM_ putStrLn with a function: \xs -> mapM_ (putStrLn xs >> putStrLn "") that also prints out the separator.

dnaq
  • 2,104
  • 1
  • 14
  • 24