
Dear Ryan,
Read instances are both (1) slow, because they take Strings, and (2) they don't allow sensible error messages! (Historical decision choosing Maybe rather than Either.)
Surprisingly, I have found (1) to be a rather small issue. Read has at least two other features that make it abysmally slow. - Read is built on top of a lexer (Prelude.lex), which in turn is based on ReadP. This means checking a lot of cases which are often useless, since while a parser would likely know which token types to expect next, 'lex' doesn't. It even causes otherwise inexplicable non- termination: For example,
read ('"' : repeat ' ') :: Int
never terminates, because 'lex' keeps on trying to determine whether the given string starts with a valid string literal or not. ReadP supports unlimited backtracking, a well-known source of bad performance in parsers (at least when the alternatives are returned as a list, which ReadP does.) - Read itself *also* supports unlimited backtracking; it's built around the ReadS type, ReadS a = String -> [(a, String)]. Again, this causes bad performance. In comparison, unfolding, say, a bytestring to a temporary list that is consumed by a parser is cheap. Of course, it's still a good idea to avoid this. I second the suggestions to use one of the modern parser libraries instead.
Argh!,
Indeed. Bertram