简体   繁体   中英

Haskell: read instance for polymorphic data type and tuples

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)

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, "")]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM