In Haskell, it often makes sense not to bother with file handles at all, but simply read or write an entire file straight from disk to memory†, and do all the partitioning/processing of the text with the pure string data structure. This avoids mixing IO and program logic, which can greatly help avoiding bugs.
-- | The interesting part of the program, which actually processes data
-- but doesn't do any IO!
reverseWords :: String -> [String]
reverseWords = reverse . words
-- | A simple wrapper that only fetches the data from disk, lets
-- 'reverseWords' do its job, and puts the result to stdout.
main :: IO ()
main = do
content <- readFile "loremipsum.txt"
mapM_ putStrLn $ reverseWords content
If loremipsum.txt
contains
Lorem ipsum dolor sit amet,
consectetur adipiscing elit
then the program will output
elit
adipiscing
consectetur
amet,
sit
dolor
ipsum
Lorem
Here, mapM_
went through the list of all words in the file, and printed each of them to a separate line with putStrLn
.
†If you think this is wasteful on memory, you have a point. Actually, Haskell's laziness can often avoid that the entire file needs to reside in memory simultaneously... but beware, this kind of lazy IO causes its own set of problems. For performance-critical applications, it often makes sense to enforce the entire file to be read at once, strictly; you can do this with the Data.Text
version of readFile
.