Compose's Show/Show1 and Read/Read1 instances no longer agree in GHC 9.6.1-alpha1
As of base-4.18.0.0
(as bundled with GHC 9.6.1-alpha1), the behavior of Compose
's Show
instance no longer agrees with its Show1
instance. By that, I mean that if you run the following program:
module Main where
import Data.Functor.Classes
import Data.Functor.Compose
ex :: Compose Maybe Maybe Int
ex = Compose Nothing
main :: IO ()
main = do
putStrLn $ showsPrec 0 ex ""
putStrLn $ showsPrec1 0 ex ""
You would expect Compose Nothing
to be printed twice. Indeed, this happens with GHC 9.4.4 and earlier:
$ runghc-9.4.4 Bug.hs
Compose Nothing
Compose Nothing
But not with GHC 9.6.1-alpha1:
$ runghc-9.6.0.20230111 Bug.hs
Compose {getCompose = Nothing}
Compose Nothing
The Show
instance now prints out the getCompose
record selector, which it did not do in previous releases.
My guess is that this is an oversight that was accidentally introduced in commit 7beb356e. The previous Show
instance for Compose
was defined as:
instance (Show1 f, Show1 g, Show a) => Show (Compose f g a) where
showsPrec = showsPrec1
instance (Show1 f, Show1 g) => Show1 (Compose f g) where
liftShowsPrec sp sl d (Compose x) =
showsUnaryWith (liftShowsPrec sp' sl') "Compose" d x
where
sp' = liftShowsPrec sp sl
sl' = liftShowList sp sl
Note that this uses showsUnaryWith
, which does not print the record selector. After commit 7beb356e, however, the Show
instance for Compose
is now derived:
deriving instance Show (f (g a)) => Show (Compose f g a)
Derived Show
instances always show record selectors if they are defined, which would explain the difference. One possible to fix the issue would be to change the Show
instance to:
instance Show (f (g a)) => Show (Compose f g a) where
showsPrec d (Compose x) =
showsUnaryWith showsPrec "Compose" d x
A similar bug exists for Compose
's now-derived Read
instance, which also disagrees with its Read1
instance. This can be seen by running this program:
module Main where
import Data.Functor.Compose
main :: IO ()
main = print (read "Compose Nothing" :: Compose Maybe Maybe Int)
This succeeds on GHC 9.4.4 and earlier:
$ runghc-9.4.4 Bug.hs
Compose Nothing
But fails with GHC 9.6.1-alpha1:
$ runghc-9.6.0.20230111 Bug.hs
Compose {getCompose = Bug.hs: Prelude.read: no parse
cc @Ericson2314