Reputation: 2411
I made Read
and Show
instances of my data, but did not understand the Read
instance
data Tests = Zero
| One Int
| Two Int Double
instance Show Tests where
show Zero = "ZERO"
show (One i) = printf "ONE %i" i
show (Two i j) = printf "TWO %i %f" i j
instance Read Tests where
readsPrec _ str = [(mkTests str, "")]
mkTests :: String -> Tests
mkTests = check . words
check :: [String] -> Tests
check ["ZERO"] = Zero
check ["ONE", i] = One (read i)
check ["TWO", i, j] = Two (read i) (read j)
check _ = error "no parse"
main :: IO ()
main = do
print Zero
print $ One 10
print $ Two 1 3.14
let x = read "ZERO" :: Tests
print x
let y = read "ONE 2" :: Tests
print y
let z = read "TWO 2 5.5" :: Tests
print z
This is output
ZERO
ONE 10
TWO 1 3.14
ZERO
ONE 2
TWO 2 5.5
Here are questions:
What is recommend way to implement Read
instance?
Read
class is readsPrec | readPrec
and readPrec :: ReadPrec a
description wroteProposed replacement for readsPrec using new-style parsers (GHC only).
readPrec
instead, How? I can't find any example on the net that I can understand.new-style parsers
, is it parsec
?What is the first Int
argument of readsPrec :: Int -> ReadS a , is using for?
Is there anyway to somehow deriving Read
from Show
?
In the past I could use deriving (Show,Read)
to most of the job. But this time I want to move to next level.
Upvotes: 3
Views: 1769
Reputation: 106
Int
argument to readsPrec
is for dealing with precedence when parsing. This might matter when you want to parse arithmetic expressions. You can choose to fail parsing if the precedence is higher than the precedence of the current operator.Read
from Show
isn't possible unfortunately.Here are a couple of snippets that show how I would implement Read
using ReadPrec
.
ReadPrec example:
instance Read Tests where
readPrec = choice [pZero, pOne, pTwo] where
pChar c = do
c' <- get
if c == c'
then return c
else pfail
pZero = traverse pChar "ZERO" *> pure Zero
pOne = One <$> (traverse pChar "ONE " *> readPrec)
pTwo = Two <$> (traverse pChar "TWO " *> readPrec) <*> readPrec
In general implementing Read is less intuitive than more heavyweight parsers. Depending on what you want to parse I highly suggest learning parsec or attoparsec since they are extremely useful when you want to parse even more complicated things.
Upvotes: 1