Parsing of
Strings, producing values.
Derived instances of
Read make the following assumptions, which
derived instances of
Show obey:
- If the constructor is defined to be an infix operator, then the
derived Read instance will parse only infix applications of the
constructor (not the prefix form).
- Associativity is not used to reduce the occurrence of parentheses,
although precedence may be.
- If the constructor is defined using record syntax, the derived
Read will parse only the record-syntax form, and furthermore,
the fields must be given in the same order as the original
declaration.
- The derived Read instance allows arbitrary Haskell
whitespace between tokens of the input string. Extra parentheses are
also allowed.
For example, given the declarations
infixr 5 :^:
data Tree a = Leaf a | Tree a :^: Tree a
the derived instance of
Read in Haskell 2010 is equivalent to
instance (Read a) => Read (Tree a) where
readsPrec d r = readParen (d > app_prec)
(\r -> [(Leaf m,t) |
("Leaf",s) <- lex r,
(m,t) <- readsPrec (app_prec+1) s]) r
++ readParen (d > up_prec)
(\r -> [(u:^:v,w) |
(u,s) <- readsPrec (up_prec+1) r,
(":^:",t) <- lex s,
(v,w) <- readsPrec (up_prec+1) t]) r
where app_prec = 10
up_prec = 5
Note that right-associativity of
:^: is unused.
The derived instance in GHC is equivalent to
instance (Read a) => Read (Tree a) where
readPrec = parens $ (prec app_prec $ do
Ident "Leaf" <- lexP
m <- step readPrec
return (Leaf m))
+++ (prec up_prec $ do
u <- step readPrec
Symbol ":^:" <- lexP
v <- step readPrec
return (u :^: v))
where app_prec = 10
up_prec = 5
readListPrec = readListPrecDefault
Why do both
readsPrec and
readPrec exist, and why does
GHC opt to implement
readPrec in derived
Read instances
instead of
readsPrec? The reason is that
readsPrec is
based on the
ReadS type, and although
ReadS is mentioned
in the Haskell 2010 Report, it is not a very efficient parser data
structure.
readPrec, on the other hand, is based on a much more efficient
ReadPrec datatype (a.k.a "new-style parsers"), but its
definition relies on the use of the
RankNTypes language
extension. Therefore,
readPrec (and its cousin,
readListPrec) are marked as GHC-only. Nevertheless, it is
recommended to use
readPrec instead of
readsPrec
whenever possible for the efficiency improvements it brings.
As mentioned above, derived
Read instances in GHC will
implement
readPrec instead of
readsPrec. The default
implementations of
readsPrec (and its cousin,
readList)
will simply use
readPrec under the hood. If you are writing a
Read instance by hand, it is recommended to write it like so:
instance Read T where
readPrec = ...
readListPrec = readListPrecDefault