Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC

Commits:

9 changed files:

Changes:

  • changelog.d/generically-mconcat
    1
    +section: base
    
    2
    +synopsis: Add definition for Generically's `mconcat` in terms of the type variable's Semigroup instance instead of using the generically derived version.
    
    3
    +issues: #27245
    
    4
    +mrs: !16011

  • libraries/base/changelog.md
    ... ... @@ -6,6 +6,7 @@
    6 6
       * Add `Data.List.NonEmpty.{zip{3..7},zipWith{3..7},unzip{3..7}}` ([CLC proposal #409)(https://github.com/haskell/core-libraries-committee/issues/409))
    
    7 7
       * Ensure that `Data.List.elem` and `notElem` can be specialized even when no list fusion happens. ([CLC proposal #412)(https://github.com/haskell/core-libraries-committee/issues/412))
    
    8 8
       * Introduce `Data.Double` and `Data.Float` modules. ([CLC proposal #378](https://github.com/haskell/core-libraries-committee/issues/378))
    
    9
    +  * Change `Generically a`'s `Monoid` definition to require a `Semigroup` constraint, and define its `mconcat` using `(<>)` from that constraint. ([CLC proposal #413](https://github.com/haskell/core-libraries-committee/issues/413))
    
    9 10
     
    
    10 11
     ## 4.23.0.0 *TBA*
    
    11 12
       * Add `System.IO.hGetNewlineMode`. ([CLC proposal #370](https://github.com/haskell/core-libraries-committee/issues/370))
    

  • libraries/ghc-internal/src/GHC/Internal/Generics.hs
    1
    -{-# OPTIONS_GHC -Wno-noncanonical-monoid-instances #-}
    
    2
    -
    
    3 1
     {-# LANGUAGE CPP                        #-}
    
    4 2
     {-# LANGUAGE DataKinds                  #-}
    
    5 3
     {-# LANGUAGE DeriveFunctor              #-}
    
    ... ... @@ -744,7 +742,7 @@ import GHC.Internal.Types hiding (Any) -- clashes with the Semigroup
    744 742
     import GHC.Internal.Ix      ( Ix )
    
    745 743
     import GHC.Internal.Base    ( Alternative(..), Applicative(..), Functor(..)
    
    746 744
                        , Monad(..), MonadPlus(..), NonEmpty(..), String
    
    747
    -                   , Semigroup(..), Void )
    
    745
    +                   , Semigroup(..), Void)
    
    748 746
     import GHC.Internal.Err (errorWithoutStackTrace)
    
    749 747
     import GHC.Internal.Classes ( Eq(..), Ord(..) )
    
    750 748
     import GHC.Internal.Enum    ( Bounded, Enum )
    
    ... ... @@ -1437,6 +1435,10 @@ class Generic1 (f :: k -> Type) where
    1437 1435
     -- type/ like 'Generically' decouples the instance from the type
    
    1438 1436
     -- class.
    
    1439 1437
     --
    
    1438
    +-- Note that if you don't generate parent and child instances using the same
    
    1439
    +-- method, the result may be incongruous; for example, in previous versions
    
    1440
    +-- `mconcat` didn't use the correct `(<>)`, instead preferring a Generic version.
    
    1441
    +--
    
    1440 1442
     -- @since base-4.17.0.0
    
    1441 1443
     newtype Generically a = Generically a
    
    1442 1444
     
    
    ... ... @@ -1446,12 +1448,14 @@ instance (Generic a, Semigroup (Rep a ())) => Semigroup (Generically a) where
    1446 1448
       Generically a <> Generically b = Generically (to (from a <> from b :: Rep a ()))
    
    1447 1449
     
    
    1448 1450
     -- | @since base-4.17.0.0
    
    1449
    -instance (Generic a, Monoid (Rep a ())) => Monoid (Generically a) where
    
    1451
    +instance (Generic a, Semigroup a, Monoid (Rep a ())) => Monoid (Generically a) where
    
    1450 1452
       mempty :: Generically a
    
    1451 1453
       mempty = Generically (to (mempty :: Rep a ()))
    
    1452 1454
     
    
    1453
    -  mappend :: Generically a -> Generically a -> Generically a
    
    1454
    -  mappend = (<>)
    
    1455
    +  -- https://github.com/haskell/core-libraries-committee/issues/324
    
    1456
    +  mconcat :: [Generically a] -> Generically a
    
    1457
    +  mconcat = foldr (coerce @(a -> a -> a) (<>)) mempty
    
    1458
    +  {-# INLINE mconcat #-}
    
    1455 1459
     
    
    1456 1460
     -- | A type whose instances are defined generically, using the
    
    1457 1461
     -- 'Generic1' representation. 'Generically1' is a higher-kinded
    

  • testsuite/tests/generics/T27245.hs
    1
    +
    
    2
    +{-# LANGUAGE DerivingVia #-}
    
    3
    +{-# LANGUAGE UndecidableInstances #-}
    
    4
    +{-# LANGUAGE AllowAmbiguousTypes #-}
    
    5
    +{-# LANGUAGE ScopedTypeVariables #-}
    
    6
    +
    
    7
    +import GHC.Generics
    
    8
    +import Data.Coerce
    
    9
    +import Data.Semigroup
    
    10
    +import Data.List.NonEmpty qualified as NE
    
    11
    +import Control.Exception
    
    12
    +
    
    13
    +main :: IO ()
    
    14
    +main = do
    
    15
    +  let l1 = L [1]
    
    16
    +      l2 = L [2]
    
    17
    +  -- check append functions; this is a regression test for later down the line
    
    18
    +  print ("sappend", l1 <> l2)
    
    19
    +  print ("mappend", l1 `mappend` l2)
    
    20
    +  print ("gappend", l1 `gappend` l2)
    
    21
    +  -- when `mappend` is removed from `Monoid`, `mappend`'s definition will be
    
    22
    +  -- `mappend = (<>)` at the top level, removing the above `mappend = gappend` issue
    
    23
    +
    
    24
    +  -- check concat functions
    
    25
    +  -- We have the defined method functions, the generic variants, and the
    
    26
    +  -- default implementations written out again
    
    27
    +  let ls = [l1, l2]
    
    28
    +      lsNE = l1 NE.:| [l2]
    
    29
    +  print ("sconcat", sconcat lsNE)
    
    30
    +  print ("mconcat", mconcat ls)
    
    31
    +  print ("gsconcat", gsconcat lsNE)
    
    32
    +  print ("gmconcat", gmconcat ls)
    
    33
    +  print ("dsconcat", dsconcat lsNE)
    
    34
    +  print ("dmconcatMappend", dmconcatMappend ls) -- uses `mappend` which is incorrect, see above
    
    35
    +  print ("dmconcatSappend", dmconcatSappend ls)
    
    36
    +  print ("dmconcatUsingSconcat", dmconcatUsingSconcat ls)
    
    37
    +
    
    38
    +  let undefinedList = l1 : undefined
    
    39
    +      fOn s f = print ("strictness " <> s, f undefinedList)
    
    40
    +  (fOn "mconcat" mconcat `finally` -- derived instance is fine, shows
    
    41
    +    fOn "gmconcat" gmconcat `finally` -- this is too strict - using mappend on lists needs all lists
    
    42
    +    fOn "dmconcatMappend" dmconcatMappend `finally` -- also too strict for the above
    
    43
    +    fOn "dmconcatSappend" dmconcatSappend `finally` -- correct strictness, shows
    
    44
    +    fOn "dmconcatUsingSconcat" dmconcatUsingSconcat -- sconcat is too strict as well
    
    45
    +    ) `catch` \(_ :: SomeException) -> pure ()
    
    46
    +
    
    47
    +newtype L a = L [a]
    
    48
    +  deriving (Generic, Show, Eq)
    
    49
    +  deriving Monoid via (Generically (L a))
    
    50
    +
    
    51
    +-- semigroup instance not derived with Generically, so it could be mis-aligned
    
    52
    +-- with generic monoid definition
    
    53
    +instance Semigroup (L a) where
    
    54
    +  L [] <> l = l
    
    55
    +  l <> _ = l
    
    56
    +
    
    57
    +-- generic (<>)
    
    58
    +gappend :: forall a . (Generic a, Semigroup (Rep a ())) => a -> a -> a
    
    59
    +gappend a b = to (from a <> from b :: Rep a ())
    
    60
    +
    
    61
    +-- generic sconcat
    
    62
    +gsconcat :: forall a . (Generic a, Semigroup (Rep a ())) => NE.NonEmpty a -> a
    
    63
    +gsconcat = to . sconcat @(Rep a ()) . fmap from
    
    64
    +
    
    65
    +-- generic mconcat
    
    66
    +gmconcat :: forall a . (Generic a, Monoid (Rep a ())) => [a] -> a
    
    67
    +gmconcat = to . mconcat @(Rep a ()) . fmap from
    
    68
    +
    
    69
    +-- default sconcat
    
    70
    +dsconcat :: forall a . Semigroup a => NE.NonEmpty a -> a
    
    71
    +dsconcat (a NE.:| as) = go a as where
    
    72
    +  go b (c:cs) = b <> go c cs
    
    73
    +  go b []     = b
    
    74
    +
    
    75
    +-- default mconcat using mappend
    
    76
    +dmconcatMappend :: Monoid a => [a] -> a
    
    77
    +dmconcatMappend = foldr mappend mempty
    
    78
    +
    
    79
    +-- default mconcat using (<>), also the new generically impl
    
    80
    +dmconcatSappend :: Monoid a => [a] -> a
    
    81
    +dmconcatSappend = foldr (<>) mempty
    
    82
    +
    
    83
    +-- incorrect impl, too strict in the spine
    
    84
    +dmconcatUsingSconcat :: Monoid a => [a] -> a
    
    85
    +dmconcatUsingSconcat as = case as of
    
    86
    +  [] -> mempty
    
    87
    +  x : xs -> sconcat (x NE.:| xs)

  • testsuite/tests/generics/T27245.stdout
    1
    +("sappend",L [1])
    
    2
    +("mappend",L [1,2])
    
    3
    +("gappend",L [1,2])
    
    4
    +("sconcat",L [1])
    
    5
    +("mconcat",L [1])
    
    6
    +("gsconcat",L [1,2])
    
    7
    +("gmconcat",L [1,2])
    
    8
    +("dsconcat",L [1])
    
    9
    +("dmconcatMappend",L [1,2])
    
    10
    +("dmconcatSappend",L [1])
    
    11
    +("dmconcatUsingSconcat",L [1])
    
    12
    +("strictness mconcat",L [1])
    
    13
    +("strictness dmconcatSappend",L [1])

  • testsuite/tests/generics/all.T
    ... ... @@ -50,3 +50,4 @@ test('T19819', normal, compile_and_run, [''])
    50 50
     test('T21185', normal, compile, [''])
    
    51 51
     test('T25148a', normal, compile, [''])
    
    52 52
     test('T25148b', normal, compile, [''])
    
    53
    +test('T27245', normal, compile_and_run, [''])

  • testsuite/tests/interface-stability/base-exports.stdout
    ... ... @@ -11056,7 +11056,7 @@ instance GHC.Internal.Base.Monoid ghc-internal-10.100.0:GHC.Internal.Event.Inter
    11056 11056
     instance GHC.Internal.Base.Monoid ghc-internal-10.100.0:GHC.Internal.Event.Internal.Types.Lifetime -- Defined in ‘ghc-internal-10.100.0:GHC.Internal.Event.Internal.Types’
    
    11057 11057
     instance forall k (f :: k -> *) (p :: k) (g :: k -> *). (GHC.Internal.Base.Monoid (f p), GHC.Internal.Base.Monoid (g p)) => GHC.Internal.Base.Monoid ((GHC.Internal.Generics.:*:) f g p) -- Defined in ‘GHC.Internal.Generics’
    
    11058 11058
     instance forall k2 k1 (f :: k2 -> *) (g :: k1 -> k2) (p :: k1). GHC.Internal.Base.Monoid (f (g p)) => GHC.Internal.Base.Monoid ((GHC.Internal.Generics.:.:) f g p) -- Defined in ‘GHC.Internal.Generics’
    
    11059
    -instance forall a. (GHC.Internal.Generics.Generic a, GHC.Internal.Base.Monoid (GHC.Internal.Generics.Rep a ())) => GHC.Internal.Base.Monoid (GHC.Internal.Generics.Generically a) -- Defined in ‘GHC.Internal.Generics’
    
    11059
    +instance forall a. (GHC.Internal.Generics.Generic a, GHC.Internal.Base.Semigroup a, GHC.Internal.Base.Monoid (GHC.Internal.Generics.Rep a ())) => GHC.Internal.Base.Monoid (GHC.Internal.Generics.Generically a) -- Defined in ‘GHC.Internal.Generics’
    
    11060 11060
     instance forall k c i (p :: k). GHC.Internal.Base.Monoid c => GHC.Internal.Base.Monoid (GHC.Internal.Generics.K1 i c p) -- Defined in ‘GHC.Internal.Generics’
    
    11061 11061
     instance forall k (f :: k -> *) (p :: k) i (c :: GHC.Internal.Generics.Meta). GHC.Internal.Base.Monoid (f p) => GHC.Internal.Base.Monoid (GHC.Internal.Generics.M1 i c f p) -- Defined in ‘GHC.Internal.Generics’
    
    11062 11062
     instance forall p. GHC.Internal.Base.Monoid p => GHC.Internal.Base.Monoid (GHC.Internal.Generics.Par1 p) -- Defined in ‘GHC.Internal.Generics’
    

  • testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
    ... ... @@ -11091,7 +11091,7 @@ instance forall m. GHC.Internal.Base.Monoid m => GHC.Internal.Base.Monoid (Data.
    11091 11091
     instance forall a. GHC.Internal.Base.Monoid a => GHC.Internal.Base.Monoid (GHC.Internal.STM.STM a) -- Defined in ‘GHC.Internal.STM’
    
    11092 11092
     instance forall k (f :: k -> *) (p :: k) (g :: k -> *). (GHC.Internal.Base.Monoid (f p), GHC.Internal.Base.Monoid (g p)) => GHC.Internal.Base.Monoid ((GHC.Internal.Generics.:*:) f g p) -- Defined in ‘GHC.Internal.Generics’
    
    11093 11093
     instance forall k2 k1 (f :: k2 -> *) (g :: k1 -> k2) (p :: k1). GHC.Internal.Base.Monoid (f (g p)) => GHC.Internal.Base.Monoid ((GHC.Internal.Generics.:.:) f g p) -- Defined in ‘GHC.Internal.Generics’
    
    11094
    -instance forall a. (GHC.Internal.Generics.Generic a, GHC.Internal.Base.Monoid (GHC.Internal.Generics.Rep a ())) => GHC.Internal.Base.Monoid (GHC.Internal.Generics.Generically a) -- Defined in ‘GHC.Internal.Generics’
    
    11094
    +instance forall a. (GHC.Internal.Generics.Generic a, GHC.Internal.Base.Semigroup a, GHC.Internal.Base.Monoid (GHC.Internal.Generics.Rep a ())) => GHC.Internal.Base.Monoid (GHC.Internal.Generics.Generically a) -- Defined in ‘GHC.Internal.Generics’
    
    11095 11095
     instance forall k c i (p :: k). GHC.Internal.Base.Monoid c => GHC.Internal.Base.Monoid (GHC.Internal.Generics.K1 i c p) -- Defined in ‘GHC.Internal.Generics’
    
    11096 11096
     instance forall k (f :: k -> *) (p :: k) i (c :: GHC.Internal.Generics.Meta). GHC.Internal.Base.Monoid (f p) => GHC.Internal.Base.Monoid (GHC.Internal.Generics.M1 i c f p) -- Defined in ‘GHC.Internal.Generics’
    
    11097 11097
     instance forall p. GHC.Internal.Base.Monoid p => GHC.Internal.Base.Monoid (GHC.Internal.Generics.Par1 p) -- Defined in ‘GHC.Internal.Generics’
    

  • testsuite/tests/interface-stability/base-exports.stdout-mingw32
    ... ... @@ -11316,7 +11316,7 @@ instance forall a. GHC.Internal.Base.Monoid a => GHC.Internal.Base.Monoid (GHC.I
    11316 11316
     instance GHC.Internal.Base.Monoid GHC.Internal.Event.Windows.EventData -- Defined in ‘GHC.Internal.Event.Windows’
    
    11317 11317
     instance forall k (f :: k -> *) (p :: k) (g :: k -> *). (GHC.Internal.Base.Monoid (f p), GHC.Internal.Base.Monoid (g p)) => GHC.Internal.Base.Monoid ((GHC.Internal.Generics.:*:) f g p) -- Defined in ‘GHC.Internal.Generics’
    
    11318 11318
     instance forall k2 k1 (f :: k2 -> *) (g :: k1 -> k2) (p :: k1). GHC.Internal.Base.Monoid (f (g p)) => GHC.Internal.Base.Monoid ((GHC.Internal.Generics.:.:) f g p) -- Defined in ‘GHC.Internal.Generics’
    
    11319
    -instance forall a. (GHC.Internal.Generics.Generic a, GHC.Internal.Base.Monoid (GHC.Internal.Generics.Rep a ())) => GHC.Internal.Base.Monoid (GHC.Internal.Generics.Generically a) -- Defined in ‘GHC.Internal.Generics’
    
    11319
    +instance forall a. (GHC.Internal.Generics.Generic a, GHC.Internal.Base.Semigroup a, GHC.Internal.Base.Monoid (GHC.Internal.Generics.Rep a ())) => GHC.Internal.Base.Monoid (GHC.Internal.Generics.Generically a) -- Defined in ‘GHC.Internal.Generics’
    
    11320 11320
     instance forall k c i (p :: k). GHC.Internal.Base.Monoid c => GHC.Internal.Base.Monoid (GHC.Internal.Generics.K1 i c p) -- Defined in ‘GHC.Internal.Generics’
    
    11321 11321
     instance forall k (f :: k -> *) (p :: k) i (c :: GHC.Internal.Generics.Meta). GHC.Internal.Base.Monoid (f p) => GHC.Internal.Base.Monoid (GHC.Internal.Generics.M1 i c f p) -- Defined in ‘GHC.Internal.Generics’
    
    11322 11322
     instance forall p. GHC.Internal.Base.Monoid p => GHC.Internal.Base.Monoid (GHC.Internal.Generics.Par1 p) -- Defined in ‘GHC.Internal.Generics’