Reputation: 3045
Let's say I've got a polymorphic data type for a frame:
data Frame a = Frame {
fdata :: V.Vector (V.Vector a)
, frows :: Int
, fcols :: Int
}
makeFrame :: [[a]] -> Frame a
makeFrame s = ...
And I want its text representation to look exactly like a list of lists:
instance Show a => Show (Frame a) where
show (Frame m _ _) = show $ V.toList $ V.toList <$> m
instance Read a => Read (Frame a) where
readsPrec _ value = [makeFrame $ read value, "")]
I was pretty happy with my read function until I found out that it doesn't really work when a frame is inside a tuple:
-- works
> let x = read $ show $ makeFrame [[1,2], [3,4]] :: Frame Int
> :t x
x :: Frame Int
-- doesn't work
> read $ show $ (1, makeFrame [[1,2], [3,4]]) :: (Int, Frame Int)
*** Exception: Prelude.read: no parse
-- meanwhile
> let x = read $ show $ (1, makeFrame [[1,2], [3,4]]) :: (Int, [[Int]])
> :t x
x :: (Int, [[Int]])
Why does an innocent embedding my data type into a tuple somehow changes the way the whole thing is parsed? What am I missing?
UPDATE:
Just in case, a working read implementation:
instance Read a => Read (Frame a) where
readsPrec d v = do (lst, rst) <- readsPrec d v
return (makeFrame lst, rst)
Upvotes: 1
Views: 347
Reputation: 91827
Your readsPrec
instance always returns ""
for the remainder, meaning that it discards all characters after the end of the value it read. Here, that's the dangling )
denoting the close of the tuple: the tuple can't be parsed, because you threw that character away.
You need to use the readsPrec
instance of the thing you're parsing, to know how many characters it consumed. I'll use a simpler newtype than yours, so as to be compilable with no external dependencies:
newtype Wrapper a = Wrapper a
instance Show a => Show (Wrapper a) where
show (Wrapper x) = 'w':show x
instance Read a => Read (Wrapper a) where
readsPrec n ('w':s) = [(Wrapper x, r) | (x, r) <- readsPrec n s]
This works, but if I replace my Read
instance with one analogous to yours, I get the same error: it can't parse while inside of another data structure.
-- totally broken instance
instance Read a => Read (Wrapper a) where
readsPrec _ ('w':s) = [(Wrapper $ read s, "")]
Upvotes: 5