\begin{haskell}{PlainTextIO}
> module PlainTextIO( module MaybeStateT, module PlainTextIO ) where
> import MaybeStateT
> import Char(isSpace)--1.3
\end{haskell}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section {Functions for Reading Data}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        The function \verb~readElements~ reads a list from a character
stream where that stream contains just the plain-text representations
of the elements of the list one after the other but {\em without\/}
the Haskell list notation, i.e., without the starting and ending
square bracks and commas between the elements.  It is important to
note that it is {\em only\/} intended for reading from character
streams that contain {\em only\/} the desired list elements and
nothing else; any characters which can't be parsed to a produce an
element of the desired type will cause a fatal error.
        Most often, \verb~readElements~ will be used to read the
contents of a file.  However, \verb~readElements~ can be used to
extract lists from any character stream---provided that the stream
contains nothing but legal list elements---so another common use might
be to use it to extract lists from the end of each line of a file,
e.g., a pronunciation dictionary.
        The reason we explicitly drop whitespace prior to applying
\verb~reads~ is that this allows us to easily check for the
end-of-file condition if \verb~reads~ can't produce a parse.  If
\verb~reads~ can't produce a parse and we haven't reached the end of
the file, we halt the program and print out a message. That message
includes up to 32 characters from the input stream to help the user
find the problem.
        \begin{haskell}{readElements}
> readElements :: (Read a) => [Char] -> [a]
> readElements cs =
>       let cs' = dropWhile isSpace cs in
>       case reads cs' of
>       [(x,cs'')]   -> x : readElements cs''
>
>       []           -> if null cs'
>                       then []
>                       else error ("readElements: unparsable chars \ 
>                                  \encountered:\n\n" ++ take 32 cs'
>                                  ++ "\n")
>
>       _            -> error ("readElements: ambiguous parse:\n\n"
>                              ++ take 32 cs' ++ "\n")
\end{haskell}
        \fixhaskellspacing\begin{haskell}{readsItem}
> readsItem :: (Read a) => MST [Char] a
> readsItem cs =
>       case reads cs of
>       [(a, cs')] -> Just (a, cs')
>       _          -> Nothing
\end{haskell}
        Some special versions of \verb~readsItem~ for when the type
checker would have difficulty deriving the type of the data to be
read.
        \begin{haskell}{readsInt}
> readsInt :: MST [Char] Int
> readsInt = readsItem
\end{haskell}
        \fixhaskellspacing\begin{haskell}{readsFloat}
> readsFloat :: MST [Char] Float
> readsFloat = readsItem
\end{haskell}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section {Functions for ``Pretty Printing''}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Another way of defining pprintElements might be
        pprintElements f = unlines . map f
where f is a showing function, but then we don't have the
third-argument accumulator string.
        \begin{haskell}{pprintElements}
> pprintElements :: (a -> String -> String) -> [a] -> String -> String
> pprintElements  f  (x:xs)  s =
>       f x ('\n' : pprintElements f xs s)
> pprintElements  _   []     s = s
\end{haskell}
        \fixhaskellspacing\begin{haskell}{pprintAsList}
> pprintAsList :: (a -> String -> String) -> [a] -> String -> String
> pprintAsList  f  xs    s = '[' : pprintAsList' f xs s
> pprintAsList' _  []    s = "]\n" ++ s
> pprintAsList' f (x:xs) s
>       | null xs        = f x (" ]\n" ++ s)
>       | otherwise      = f x (",\n " ++ pprintAsList' f xs s)
\end{haskell}
        \fixhaskellspacing\begin{haskell}{consNewLine}
> consNewline :: String -> String
> consNewline = ('\n' :)
\end{haskell}
 |