\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}
|