GHC can't derive Read
or Show
for complicated GADTs, so I attempted to define custom instances below that satisfy read . show == id
. I've simplified the example as much as possible (while still triggering the runtime error like my real code). I decided to let GHC do the heavy lifting of writing Read
and Show
instances by making newtype
wrappers for each GADT constructor (more accurately: for each type output by the GADT). In the Read
/Show
instances, I simply read/show the newtype wrapper and convert where necessary. I assumed this was foolproof: I'm letting GHC define all of the non-trivial instances. However, I seem to have done something wrong.
In my real code, Foo
below is a complicated GADT that GHC won't derive Show
or Read
for. Since Foo
is a wrapper (in part) around a newtype, I use the derived Show
/Read
instances for that.
{-# LANGUAGE FlexibleContexts, FlexibleInstances, GADTs, ScopedTypeVariables #-}
import Text.Read (Read(readPrec))
newtype Bar r = Bar r deriving (Show, Read)
newtype Foo r = Foo (Bar r)
-- use the GHC-derived Show/Read for Bar
instance (Show r) => Show (Foo r) where
show (Foo x) = show x
instance (Read r) => Read (Foo r) where
readPrec = Foo <$> readPrec
This instance seems to work: I can call read . show
and I get back the input.
Now I have a wrapper around Foo
:
data U t rep r where
U1 :: t r -> U t Int r
U2 :: t r -> U t Char r
-- use the Read/Show instances for U1Wrap and U2Wrap
newtype U1Wrap t r = U1Wrap {unU1Wrap :: t r} deriving (Show, Read)
newtype U2Wrap t r = U2Wrap (t r) deriving (Show, Read)
instance (Read (t r)) => Read (U t Int r) where
readPrec = (U1 . unU1Wrap) <$> readPrec
instance (Read (U2Wrap t r)) => Read (U t Char r) where
readPrec = do
x <- readPrec
return $ case x of
(U2Wrap y) -> U2 y
instance (Show (t r)) => Show (U t Int r) where
show (U1 x) = show $ U1Wrap x
instance (Show (t r)) => Show (U t Char r) where
show (U2 x) = show (U2Wrap x :: U2Wrap t r)
Like Foo
, U
is a complicated GADT, so I define custom newtype wrappers for each output type of the GADT. Unfortunately, my Show
/Read
instances don't work:
main :: IO ()
main = do
let x = U1 $ Foo $ Bar 3
y = U2 $ Foo $ Bar 3
print $ show (read (show x) `asTypeOf` x)
print $ show (read (show y) `asTypeOf` y)
main
prints the first line, but I get Exception: Prelude.read: no parse
on the second line.
This is my first time using Read
, so I suspect I'm doing something incorrectly, though I don't see what that is.
My questions are:
- Why am I getting this error, and logically how can I fix it? (There are several ways to poke the minimal example above to make the error go away, but I can't do those things in my real code.)
- Is there a different/better high-level approach to
Read
ing GADTs?
deriving instance Read (t r) => Read (U t rep r)
? Is that not accepted? Would life be easier if you defined your GADT to have only two parameters,tr
andrep
, and defined a newtype around it to combinet
withr
? – dfeuerShow
, notRead
.Show
is much easier to derive. – dfeuerRead
instance has to be manually derived, I figure I have to have a correspondingShow
instance, which is certainly not what GHC would generate (even if it could). – crockeea