Home > Enterprise >  Outputting Multiple Files in Haskell
Outputting Multiple Files in Haskell

Time:10-13

I'm writing code that can read one or multiple files within a directory and I am having trouble having it output the contents (in my case) of both text files. My code can currently output the contents of either text file within the terminal, but not both at the same time. I also included an error message in the event that if the file or directory does not exist. I also want to modify my code so that if only one text file exists within the directory, it outputs the content of that file and provides an error message for if the second file does not exist at the same time like so:

cabal -v0 run cat test/loremm.txt test/haiku.txt (loremm.txt does not exist within the directory)

Output: cat: test/loremm.txt: No such file or directory\nHaskell's cryptic form\nis natural to some folks\nand so is haiku\n"

My Code:

module Main where
import System.Environment
import System.IO (readFile)
import System.Directory


main :: IO ()
main = do fs <- getArgs
          contents <- readFiles fs
          putStrLn (head contents)

readFiles :: [String] -> IO [String]
readFiles [] = return []
readFiles (x:xs) = do
    doesExist <- doesFileExist x
    if doesExist then do      
        contents <- readFile x
        others <- readFiles xs
        return (contents:others)
    else do 
        others <- readFiles xs
        return (("cat: "    x    ": No such file or directory\n") : others)

CodePudding user response:

The contents variable in main is a list containing a string per file, containing the contents of each. Thus, doing putStrLn (head contents) prints only the contents of the first file. You probably meant putStrLn (concat contents) instead.

On an unrelated note, your readFiles method would be much simpler written in terms of traverse, like this:

readFiles = traverse $ \x -> do
    doesExist <- doesFileExist x
    if doesExist then
        readFile x
    else
        return ("cat: "    x    ": No such file or directory\n")

The way to notice this is that what you're doing is basically a map, except that the result type of each thing gets wrapped in the IO monad.

  • Related