haskellghc

How to use GHC’s `ReadPrec`?


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.


Solution

  • 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.