
Using Show & Read is the only really portable way to do this, unfortunately.
Well, it's not really portable... Try the program at the end of this file, by first executing hugsMain in hugs, exiting and then running main in ghc or ghci, and you'll see:
| Cons{hd='a',tl=(Cons{hd='b',tl=Nil})} | *** Exception: Prelude.read: no parse
So, at least ghc and hugs disagree...
It appears that nhc98 and DrIFT get it wrong as well, whilst hbc gets it right, like Hugs (although hbc diverges from the Report by adding extra whitespace). Can anyone spot the fault in the derived instance of Read produced by DrIFT? Regards, Malcolm
data List a = Nil | Cons { hd :: a, tl :: List a }
{-* Generated by DrIFT-v1.0 : Look, but Don't Touch. *-} instance (Show a) => Show (List a) where showsPrec d (Nil) = showString "Nil" showsPrec d (Cons aa ab) = showParen (d >= 10) (showString "Cons" . showChar '{' . showString "hd" . showChar '=' . showsPrec 10 aa . showChar ',' . showString "tl" . showChar '=' . showsPrec 10 ab . showChar '}')
instance (Read a) => Read (List a) where readsPrec d input = (\ inp -> [((Nil) , rest) | ("Nil" , rest) <- lex inp]) input ++ readParen (d > 9) (\ inp -> [((Cons aa ab) , rest) | ("Cons" , inp) <- lex inp , ("{" , inp) <- lex inp , ("hd" , inp) <- lex inp , ("=" , inp) <- lex inp , (aa , inp) <- readsPrec 10 inp , ("," , inp) <- lex inp , ("tl" , inp) <- lex inp , ("=" , inp) <- lex inp , (ab , inp) <- readsPrec 10 inp , ("}" , rest) <- lex inp]) input