Commit 9cfef167 authored by Ryan Scott's avatar Ryan Scott Committed by Ben Gamari

Add Read1/Read2 methods defined in terms of ReadPrec

This adds new methods `liftReadList(2)` and `liftReadListPrec(2)` to the
`Read1`/`Read2` classes which are defined in terms of `ReadPrec` instead
of `ReadS`. This also adds related combinators and changes existing
`Read1` and `Read2` instances to be defined in terms of the new methods.

Reviewers: hvr, austin, bgamari

Reviewed By: bgamari

Subscribers: thomie

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

GHC Trac Issues: #12358
parent 9306db05
......@@ -111,6 +111,12 @@ See ``changelog.md`` in the ``base`` package for full release notes.
- ``Data.Type.Coercion`` now provides ``gcoerceWith``, which is analogous to
``gcastWith`` from ``Data.Type.Equality``.
- The ``Read1`` and ``Read2`` classes in ``Data.Functor.Classes`` have new
methods, ``liftReadList(2)`` and ``liftReadListPrec(2)``, that are defined in
terms of ``ReadPrec`` instead of ``ReadS``. This matches the interface
provided in GHC's version of the ``Read`` class, and allows users to write
more efficient ``Read1`` and ``Read2`` instances.
binary
~~~~~~
......
......@@ -152,7 +152,7 @@ Numbers, basic types, and built-in classes
``Num`` superclasses
The ``Num`` class does not have ``Show`` or ``Eq`` superclasses.
You can make code that works with both Haskell98/Haskell2010 and GHC
by:
......@@ -178,6 +178,16 @@ Numbers, basic types, and built-in classes
- Always define the ``bit``, ``testBit`` and ``popCount`` methods
in ``Bits`` instances.
``Read`` class methods
The ``Read`` class has two extra methods, ``readPrec`` and
``readListPrec``, that are not found in the Haskell 2010 since they rely
on the ``ReadPrec`` data type, which requires the :ghc-flag:`-XRankNTypes`
extension. GHC also derives ``Read`` instances by implementing ``readPrec``
instead of ``readsPrec``, and relies on a default implementation of
``readsPrec`` that is defined in terms of ``readPrec``. GHC adds these two
extra methods simply because ``ReadPrec`` is more efficient than ``ReadS``
(the type on which ``readsPrec`` is based).
Extra instances
The following extra instances are defined: ::
......
This diff is collapsed.
......@@ -28,6 +28,7 @@ import Data.Data (Data)
import Data.Foldable (Foldable(foldMap))
import Data.Traversable (Traversable(traverse))
import GHC.Generics (Generic, Generic1)
import Text.Read (Read(..), readListDefault, readListPrecDefault)
infixr 9 `Compose`
......@@ -50,11 +51,14 @@ instance (Ord1 f, Ord1 g) => Ord1 (Compose f g) where
-- | @since 4.9.0.0
instance (Read1 f, Read1 g) => Read1 (Compose f g) where
liftReadsPrec rp rl = readsData $
readsUnaryWith (liftReadsPrec rp' rl') "Compose" Compose
liftReadPrec rp rl = readData $
readUnaryWith (liftReadPrec rp' rl') "Compose" Compose
where
rp' = liftReadsPrec rp rl
rl' = liftReadList rp rl
rp' = liftReadPrec rp rl
rl' = liftReadListPrec rp rl
liftReadListPrec = liftReadListPrecDefault
liftReadList = liftReadListDefault
-- | @since 4.9.0.0
instance (Show1 f, Show1 g) => Show1 (Compose f g) where
......@@ -76,7 +80,10 @@ instance (Ord1 f, Ord1 g, Ord a) => Ord (Compose f g a) where
-- | @since 4.9.0.0
instance (Read1 f, Read1 g, Read a) => Read (Compose f g a) where
readsPrec = readsPrec1
readPrec = readPrec1
readListPrec = readListPrecDefault
readList = readListDefault
-- | @since 4.9.0.0
instance (Show1 f, Show1 g, Show a) => Show (Compose f g a) where
......
......@@ -31,6 +31,7 @@ import Data.Functor.Classes
import Data.Monoid (mappend)
import Data.Traversable (Traversable(traverse))
import GHC.Generics (Generic, Generic1)
import Text.Read (Read(..), readListDefault, readListPrecDefault)
-- | Lifted product of functors.
data Product f g a = Pair (f a) (g a)
......@@ -47,8 +48,11 @@ instance (Ord1 f, Ord1 g) => Ord1 (Product f g) where
-- | @since 4.9.0.0
instance (Read1 f, Read1 g) => Read1 (Product f g) where
liftReadsPrec rp rl = readsData $
readsBinaryWith (liftReadsPrec rp rl) (liftReadsPrec rp rl) "Pair" Pair
liftReadPrec rp rl = readData $
readBinaryWith (liftReadPrec rp rl) (liftReadPrec rp rl) "Pair" Pair
liftReadListPrec = liftReadListPrecDefault
liftReadList = liftReadListDefault
-- | @since 4.9.0.0
instance (Show1 f, Show1 g) => Show1 (Product f g) where
......@@ -65,7 +69,10 @@ instance (Ord1 f, Ord1 g, Ord a) => Ord (Product f g a) where
-- | @since 4.9.0.0
instance (Read1 f, Read1 g, Read a) => Read (Product f g a) where
readsPrec = readsPrec1
readPrec = readPrec1
readListPrec = readListPrecDefault
readList = readListDefault
-- | @since 4.9.0.0
instance (Show1 f, Show1 g, Show a) => Show (Product f g a) where
......
......@@ -21,12 +21,13 @@ module Data.Functor.Sum (
Sum(..),
) where
import Control.Applicative ((<|>))
import Data.Data (Data)
import Data.Foldable (Foldable(foldMap))
import Data.Functor.Classes
import Data.Monoid (mappend)
import Data.Traversable (Traversable(traverse))
import GHC.Generics (Generic, Generic1)
import Text.Read (Read(..), readListDefault, readListPrecDefault)
-- | Lifted sum of functors.
data Sum f g a = InL (f a) | InR (g a)
......@@ -48,9 +49,12 @@ instance (Ord1 f, Ord1 g) => Ord1 (Sum f g) where
-- | @since 4.9.0.0
instance (Read1 f, Read1 g) => Read1 (Sum f g) where
liftReadsPrec rp rl = readsData $
readsUnaryWith (liftReadsPrec rp rl) "InL" InL `mappend`
readsUnaryWith (liftReadsPrec rp rl) "InR" InR
liftReadPrec rp rl = readData $
readUnaryWith (liftReadPrec rp rl) "InL" InL <|>
readUnaryWith (liftReadPrec rp rl) "InR" InR
liftReadListPrec = liftReadListPrecDefault
liftReadList = liftReadListDefault
-- | @since 4.9.0.0
instance (Show1 f, Show1 g) => Show1 (Sum f g) where
......@@ -67,7 +71,10 @@ instance (Ord1 f, Ord1 g, Ord a) => Ord (Sum f g a) where
compare = compare1
-- | @since 4.9.0.0
instance (Read1 f, Read1 g, Read a) => Read (Sum f g a) where
readsPrec = readsPrec1
readPrec = readPrec1
readListPrec = readListPrecDefault
readList = readListDefault
-- | @since 4.9.0.0
instance (Show1 f, Show1 g, Show a) => Show (Sum f g a) where
showsPrec = showsPrec1
......
......@@ -147,6 +147,31 @@ readParen b g = if b then mandatory else optional
-- > up_prec = 5
-- >
-- > readListPrec = readListPrecDefault
--
-- Why do both 'readsPrec' and 'readPrec' exist, and why does GHC opt to
-- implement 'readPrec' in derived 'Read' instances instead of 'readsPrec'?
-- The reason is that 'readsPrec' is based on the 'ReadS' type, and although
-- 'ReadS' is mentioned in the Haskell 2010 Report, it is not a very efficient
-- parser data structure.
--
-- 'readPrec', on the other hand, is based on a much more efficient 'ReadPrec'
-- datatype (a.k.a \"new-style parsers\"), but its definition relies on the use
-- of the @RankNTypes@ language extension. Therefore, 'readPrec' (and its
-- cousin, 'readListPrec') are marked as GHC-only. Nevertheless, it is
-- recommended to use 'readPrec' instead of 'readsPrec' whenever possible
-- for the efficiency improvements it brings.
--
-- As mentioned above, derived 'Read' instances in GHC will implement
-- 'readPrec' instead of 'readsPrec'. The default implementations of
-- 'readsPrec' (and its cousin, 'readList') will simply use 'readPrec' under
-- the hood. If you are writing a 'Read' instance by hand, it is recommended
-- to write it like so:
--
-- @
-- instance 'Read' T where
-- 'readPrec' = ...
-- 'readListPrec' = 'readListPrecDefault'
-- @
class Read a where
{-# MINIMAL readsPrec | readPrec #-}
......
......@@ -18,6 +18,11 @@
* `Data.Type.Coercion` now provides `gcoerceWith` (#12493)
* New methods `liftReadList(2)` and `liftReadListPrec(2)` in the
`Read1`/`Read2` classes that are defined in terms of `ReadPrec` instead of
`ReadS`, as well as related combinators, have been added to
`Data.Functor.Classes` (#12358)
## 4.9.0.0 *May 2016*
* Bundled with GHC 8.0
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment