haskellnested-listswritefileappendfile

How can I write every list from a nested list separately to a file?


I am trying to write every list from a nested list to the same file. However I want every list to start on a newline.

I've made this and it works, but it's very inefficient and looks bad:

appendFile "scraped.txt" (show (take 1 l))
appendFile "scraped.txt" ("\n")
let l3 = (drop 1 l)
appendFile "scraped.txt" (show (take 1 l3))
appendFile "scraped.txt" ("\n")
let l4 = (drop 1 l3)
appendFile "scraped.txt" (show (take 1 l4))
appendFile "scraped.txt" ("\n")
let l5 = (drop 1 l4)
appendFile "scraped.txt" (show (take 1 l5))
appendFile "scraped.txt" ("\n")
let l6 = (drop 1 l5)
appendFile "scraped.txt" (show (take 1 l6))
appendFile "scraped.txt" ("\n")

I tried something like the following, but I can't seem to correctly use the mapping function:

listValues :: [[String]] -> [String]
listValues :: (map . map)

appendValues :: [[String]] -> IO ()
appendValues = appendFile "scraped.txt" listValues

The txt file now looks like this, which is ok, I just want to know how I can improve my code and learn how to use the mapping function.

Title,Subtitle,Date,Author
[["Een gezonde samenleving? \226\128\156Het belang van sporten wordt onderschat\226\128\157","Teamsport","16 maart 2022","HAN redactie"]]
[["Zo vader, zo dochter","Carsten en Kirsten","10 maart 2022","HAN redactie"]]
[["Milieuvriendelijk vervoer met waterstof","Kennisclip","09 maart 2022","HAN redactie"]]
[["\"Ik heb zin in wat nog komen gaat\"","Master Mind","08 maart 2022","HAN redactie"]]
[["Oorlog in Oekra\195\175ne","Statement van het CvB","07 maart 2022","HAN redactie"]]

Solution

  • To do this in a map-like loop, you would typically use the mapM_ library function. The final underscore_ in the function name means that action results are ignored, something which suits us as we want a result type of IO ().

    It seems appropriate to get a file handle, in order to avoid asking the OS to repetitively reopen the same output file, which is wasteful.

    Possible code:

    import System.IO
    
    type FileName = String
    
    writeNestedList :: Show a => FileName -> [[a]] -> IO ()
    writeNestedList fileName xss =
        do
           fh <- openFile  fileName  WriteMode  -- get a file handle
           mapM_  ((hPutStrLn fh) . show)  xss
           hClose fh
    
    
    main :: IO ()
    main = do
       let  xss = [ ["ab","bc"] ,["de","ef"], ["gh","hi"] ]
       writeNestedList  "scraped.txt"  xss
    

    Testing:

    $ 
    $ ghc q71608762.hs  -o q71608762.x
    [1 of 1] Compiling Main             ( q71608762.hs, q71608762.o )
    Linking ./q71608762.x ...
    $ 
    $ q71608762.x
    $ 
    $ cat scraped.txt
    ["ab","bc"]
    ["de","ef"]
    ["gh","hi"]
    $