Make the Read instance for Proxy (and friends) ignore precedence
authorRyan Scott <ryan.gl.scott@gmail.com>
Tue, 22 Aug 2017 13:29:07 +0000 (09:29 -0400)
committerRyan Scott <ryan.gl.scott@gmail.com>
Tue, 22 Aug 2017 13:29:07 +0000 (09:29 -0400)
Summary:
The `Read` instance for `Proxy`, as well as a handful of other data
types in `base` which only have a single constructor, are doing something
skeevy: they're requiring that they be surrounded by parentheses if the parsing
precedence is sufficiently high. This means that `"Thing (Proxy)"` would parse,
but not `"Thing Proxy"`. But the latter really ought to parse, since there's no
need to surround a single constructor with parentheses. Indeed, that's the
output of `show (Thing Proxy)`, so the current `Read` instance for `Proxy`
violates `read . show = id`.

The simple solution is to change `readParen (d > 10)` to `readParen False` in
the `Read` instance for `Proxy`. But given that a derived `Read` instance would
essentially accomplish the same thing, but with even fewer characters, I've
opted to just replace the hand-rolled `Read` instance with a derived one.

Test Plan: make test TEST=T12874

Reviewers: ekmett, austin, hvr, goldfire, bgamari

Reviewed By: bgamari

Subscribers: rwbarton, thomie

GHC Trac Issues: #12874

Differential Revision: https://phabricator.haskell.org/D3871

libraries/base/Data/Proxy.hs
libraries/base/Data/Type/Coercion.hs
libraries/base/Data/Type/Equality.hs
libraries/base/GHC/Generics.hs
libraries/base/changelog.md
libraries/base/tests/T12874.hs [new file with mode: 0644]
libraries/base/tests/T12874.stdout [new file with mode: 0644]
libraries/base/tests/all.T

index 1ebf56c..2ebb4ab 100644 (file)
@@ -53,7 +53,9 @@ import GHC.Arr
 --
 -- >>> Proxy :: Proxy complicatedStructure
 -- Proxy
-data Proxy t = Proxy deriving Bounded
+data Proxy t = Proxy deriving ( Bounded
+                              , Read -- ^ @since 4.7.0.0
+                              )
 
 -- | A concrete, promotable proxy type, for use at the kind level
 -- There are no instances for this because it is intended at the kind level only
@@ -76,10 +78,6 @@ instance Show (Proxy s) where
   showsPrec _ _ = showString "Proxy"
 
 -- | @since 4.7.0.0
-instance Read (Proxy s) where
-  readsPrec d = readParen (d > 10) (\r -> [(Proxy, s) | ("Proxy",s) <- lex r ])
-
--- | @since 4.7.0.0
 instance Enum (Proxy s) where
     succ _               = errorWithoutStackTrace "Proxy.succ"
     pred _               = errorWithoutStackTrace "Proxy.pred"
index 2358115..2bfd9ae 100644 (file)
@@ -81,8 +81,7 @@ deriving instance Show (Coercion a b)
 deriving instance Ord  (Coercion a b)
 
 -- | @since 4.7.0.0
-instance Coercible a b => Read (Coercion a b) where
-  readsPrec d = readParen (d > 10) (\r -> [(Coercion, s) | ("Coercion",s) <- lex r ])
+deriving instance Coercible a b => Read (Coercion a b)
 
 -- | @since 4.7.0.0
 instance Coercible a b => Enum (Coercion a b) where
index 8cc34f6..09999b0 100644 (file)
@@ -125,8 +125,7 @@ deriving instance Show (a :~: b)
 deriving instance Ord  (a :~: b)
 
 -- | @since 4.7.0.0
-instance a ~ b => Read (a :~: b) where
-  readsPrec d = readParen (d > 10) (\r -> [(Refl, s) | ("Refl",s) <- lex r ])
+deriving instance a ~ b => Read (a :~: b)
 
 -- | @since 4.7.0.0
 instance a ~ b => Enum (a :~: b) where
@@ -153,8 +152,7 @@ deriving instance Show (a :~~: b)
 deriving instance Ord  (a :~~: b)
 
 -- | @since 4.10.0.0
-instance a ~~ b => Read (a :~~: b) where
-  readsPrec d = readParen (d > 10) (\r -> [(HRefl, s) | ("HRefl",s) <- lex r ])
+deriving instance a ~~ b => Read (a :~~: b)
 
 -- | @since 4.10.0.0
 instance a ~~ b => Enum (a :~~: b) where
index 14184c2..d4e9583 100644 (file)
@@ -742,7 +742,7 @@ import GHC.Base    ( Alternative(..), Applicative(..), Functor(..)
                    , Monad(..), MonadPlus(..), String, coerce )
 import GHC.Classes ( Eq(..), Ord(..) )
 import GHC.Enum    ( Bounded, Enum )
-import GHC.Read    ( Read(..), lex, readParen )
+import GHC.Read    ( Read(..) )
 import GHC.Show    ( Show(..), showString )
 
 -- Needed for metadata
@@ -775,8 +775,7 @@ instance Ord (U1 p) where
   compare _ _ = EQ
 
 -- | @since 4.9.0.0
-instance Read (U1 p) where
-  readsPrec d = readParen (d > 10) (\r -> [(U1, s) | ("U1",s) <- lex r ])
+deriving instance Read (U1 p)
 
 -- | @since 4.9.0.0
 instance Show (U1 p) where
index ab304a3..cce9fba 100644 (file)
 
   * Add instances `Semigroup` and `Monoid` for `Control.Monad.ST` (#14107).
 
+  * The `Read` instances for `Proxy`, `Coercion`, `(:~:)`, `(:~~:)`, and `U1`
+    now ignore the parsing precedence. The effect of this is that `read` will
+    be able to successfully parse more strings containing `"Proxy"` _et al._
+    without surrounding parentheses (e.g., `"Thing Proxy"`) (#12874).
+
 ## 4.10.0.0 *April 2017*
   * Bundled with GHC *TBA*
 
diff --git a/libraries/base/tests/T12874.hs b/libraries/base/tests/T12874.hs
new file mode 100644 (file)
index 0000000..cba7173
--- /dev/null
@@ -0,0 +1,9 @@
+module Main where
+
+import Data.Proxy
+
+main :: IO ()
+main = print (read "Thing Proxy" :: Thing (Proxy Int))
+
+data Thing a = Thing a
+  deriving (Read,Show)
diff --git a/libraries/base/tests/T12874.stdout b/libraries/base/tests/T12874.stdout
new file mode 100644 (file)
index 0000000..8a89660
--- /dev/null
@@ -0,0 +1 @@
+Thing Proxy
index d97d79a..970fb7e 100644 (file)
@@ -205,6 +205,7 @@ test('T12494', normal, compile_and_run, [''])
 test('T12852', when(opsys('mingw32'), skip), compile_and_run, [''])
 test('lazySTexamples', normal, compile_and_run, [''])
 test('T11760', normal, compile_and_run, ['-threaded -with-rtsopts=-N2'])
+test('T12874', normal, compile_and_run, [''])
 test('T13191',
         [ stats_num_field('bytes allocated',
                           [ (wordsize(64), 185943272, 5) ])