Assignment 7: Haskell grade summary

Due: 5:00pm, Friday, October 19. Value: 30 pts.

Complete the problem from Assignment 4 using Haskell rather than Ruby.

To do this, you'll need to read a file. Below is an example Haskell program for counting the number of lines, words, and characters in a file. This example program defines forEachLine function, a handy function that I strongly suggest using exactly as written (though passing in another function than incrCounts).

import System.IO
import Data.Map as Map
import Data.Set as Set
import Data.List as List

-- Given a file handle, a function, and a starting value,
-- execute a fold across the lines of the file. That is, return
-- f line0 x0 >>= f line1 >>= f line2 >>= ... >>= f lineZ
forEachLine :: Handle -> (String -> a -> IO a-> a -> IO a
forEachLine handle f x0 =
 do atEof <- hIsEOF handle
    if atEof then
        return x0
     else
        do line <- hGetLine handle
           x1 <- f line x0
           forEachLine handle f x1

incrCounts :: String -> (IntIntInt-> IO (IntIntInt)
incrCounts line (lswscs=
    return (ls + 1ws + length (words line), cs + length line + 1)

main :: IO ()
main =
 do handle <- openFile "essay.txt" ReadMode
    (lswscs<- forEachLine handle incrCounts (000)
    putStrLn (show ls ++ " " ++ show ws ++ " " ++ show cs)

Another useful utility function that you may want to include is diffLists: Given two lists of strings, diffLists returns a list of each element from the first list that is not in the second.

diffLists :: Ord a => [a-> [a-> [a]
diffLists allStrings exclStrings =
    let exclSet = Set.fromList exclStrings
    in List.filter (\x -> Set.notMember x exclSetallStrings

Another function that you'll definitely want is the words function included in the standard Prelude: words line constructs a list containing each space-separated word from line as a separate list element, very much like Python's line.split().

Finally, I suggest using a Map for what the Python implementation calls totals. In particular, I found Map.empty, Map.insertWith, Map.keys, and Map.toList to be particularly helpful. [Map documentation]