I want to implement an instance of read that enables me to read a string (ex: “- – 8 – 3 -“) and construct a list containing those values.
data Value a = Nul | Val a
showsValue :: (Show a) => Value a -> ShowS
showsValue (Val x) = ("Value" ++) . shows x
showsValue (Nul) = ("Nothing 0" ++)
instance Show a => Show (Value a) where
showsPrec _ x = showsValue x
instance Read a => Read (Value a) where
readsPrec _ m = readsMatrix m
readsMatrix :: (Read a) => ReadS (Value a)
readsMatrix ('-':s) = [(Nul, rest) | (' ',rest) <- reads s]
readsMatrix s = [(Val x,rest)| (x,' ':rest) <- reads s]
After performing this test:
read "- 8 - - 3" :: Value Int
I get the error *** Exception: Prelude.read: no parse
What am I doing wrong here?
update
readsMatrix ('-':s) = [(Nul, dropWhile isSpace s)]
readsMatrix s = [(Val x, dropWhile isSpace rest) | (x,rest) <- reads s]
Correcting read for Value a
First, don’t bother removing spaces, that’s all handled fine by
reads:Your read instance is now fine for single Values:
Correcting read for [Value a]
But you want to read lists as separated by spaces, so since that’s non-standard behaviour, you’ll need to write a custom
readList :: :: ReadS [Value a]So now
but unfortunately,
and even worse,
Reading a matrix
There’s no straightforward way round this that I can see, because there’s no
readListOfListsin theReadclass, so why not make a standalone functionso that
Show isn’t what I would choose
I think your
Showinstance forValueis a little misleading (Nuldoesn’t have a zero on it,Valisn’t writtenValue). Either writeso that it looks as it is or define it to match the
Readinstance