The documentation for GHC.Read
describes readPrec
only by:
Proposed replacement for readsPrec using new-style parsers (GHC only).
Other functions, types, etc. have no documentation at all. How do I use the supposedly more efficient parsing functionality in the intended way? Why is it more efficient?
The toy example I’d like to try out the new GHC approach is this:
data RoseTree a = RoseTree a [RoseTree a] deriving (Eq)
-- | A RoseTree is being displayed "label[children…]" for
-- | nonempty children and just "label" for a leaf (= tree with no children).
instance Show a => Show (RoseTree a) where
show (RoseTree label []) = show label
show (RoseTree label ts) = show label ++ show ts
-- | Parses outputs of `show` to a RoseTree.
instance Read a => Read (RoseTree a) where
readsPrec n str = do
(label, labelRemaining) <- readsPrec n str
let tsReads = readsPrec n labelRemaining
(ts, tsRemaining) <- ([], labelRemaining) : tsReads
return (RoseTree label ts, tsRemaining)
I wrote this several years back for my Bachelor’s thesis and to be honest, I don’t understand the Read
instance anymore. The code includes the Show
instance as Read
morally requires Show
and should be compatible with it.
ReadPrec
is (slightly) further documented in Text.ParserCombinators.ReadPrec. It implements the usual parser classes (Applicative
, Monad
, Alternative
), so you should be able to use it something like this:
instance Read a => Read (RoseTree a) where
-- a instance vvvvvvvv
readPrec = liftA2 RoseTree readPrec (readPrec <|> pure [])
-- [RoseTree a] instance ^^^^^^^^
readListPrec = readListPrecDefault
You may want to think how this should interact with precedence, then insert appropriate calls to step
and prec
. You might also choose to use <++
over <|>
; the former is generally more efficient but may commit to its first argument too soon and prevent certain things from parsing that otherwise ought to.