Working with the IO monad in Haskell.
Beginning of class session 19.
HaskellHomework within your local copy of your SVN repository. Do an SVN update on that folder and you’ll find a file WackyMaps.hs. Except where indicated, all your work for this assignment must be done in that file. This is so we can efficiently grade your and your classmates’ work.
The file includes the line import Data.Map (Map, empty, insert, findWithDefault). This imports a library for manipulating finite maps (also known as dictionaries) in Haskell. Experiment with the following functions until you understand what they do:
empty :: Map k a
insert :: (Ord k) => k -> a -> Map k a -> Map k a
findWithDefault :: (Ord k) => a -> k -> Map k a -> a
Can you predict the values of v1, v2, and v3 after loading the following code? (You don’t have to turn in any work for this task, but you should check your work using ghci.)
m1 = empty m2 = insert 'x' 10 m1 m3 = insert 'y' 20 m2 v1 = findWithDefault 0 'x' m3 v2 = findWithDefault 0 'y' m3 v3 = findWithDefault 0 'z' m3 m4 = insert 'y' 30 m3 v4 = findWithDefault 0 'y' m4
Implement a Wacky Prof. Quotes program as described in homework 3. Some suggestions:
String to represent professors’ names, dates, and quotes. Create type synonyms for these—Prof, Date, and Quote—so your code is more readable.
data DateQuotePair = DQPair Date Quote
deriving (Show,Read)
repl :: (Map String [DateQuotePair]) -> IO ()
repl as being like the accumulator in a tail-recursive implementation of a function.
You might want to create a main IO action to run your loop. This worked for me to start:
main :: IO () main = repl empty
After I implemented file I/O, I changed this to:
main :: IO () main = do db <- getDatabaseFromDisk repl db
getDatabaseFromDisk:
wpqFileName = "wpq.txt"
getDatabaseFromDisk :: IO (Map Prof [DateQuotePair])
getDatabaseFromDisk = catch (readAttempt) (\exc -> return empty)
where readAttempt =
do
contents <- readFile wpqFileName
let db = ((read contents) :: (Map Prof [DateQuotePair]))
{- '$!' below forces strict processing of the db
argument, rather than non-strict (lazy) processing.
This causes the entire file contents to be loaded
into memory, but prevents the problem where Haskell
gives a permission error on writing to the file
because it has finished lazily reading from the file.
-}
return $! db
I used a couple of helper IO actions named addQuote and printQuotes, with the same type as repl. I used another helper IO action with the type:
saveMap :: (Map Prof [DateQuotePair]) -> IO ()
Hint: To implement this last helper, note that the Map datatype implements the Show typeclass. That is, you can use a single show call to convert a Map into a String that could later be read by the getDatabaseFromDisk function.