diff options
author | Herbert Valerio Riedel <hvr@gnu.org> | 2017-09-05 07:29:36 +0200 |
---|---|---|
committer | Herbert Valerio Riedel <hvr@gnu.org> | 2017-09-07 23:43:53 +0200 |
commit | 8ae263ceb3566a7c82336400b09cb8f381217405 (patch) | |
tree | 535775c4f739cd23bd443557f2d8f8b939cf711e /libraries/base | |
parent | 055d73c6576bed2affaf96ef6a6b89aeb2cd2e9f (diff) | |
download | haskell-8ae263ceb3566a7c82336400b09cb8f381217405.tar.gz |
Make Semigroup a superclass of Monoid (re #14191)
Unfortunately, this requires introducing a couple of .hs-boot files to
break up import cycles (mostly to provide class & typenames in order to
be able to write type signatures).
This does not yet re-export `(<>)` from Prelude (while the class-name
`Semigroup` is reexported); that will happen in a future commit.
Test Plan: local ./validate passed
Reviewers: ekmett, austin, bgamari, erikd, RyanGlScott
Reviewed By: ekmett, RyanGlScott
GHC Trac Issues: #14191
Differential Revision: https://phabricator.haskell.org/D3927
Diffstat (limited to 'libraries/base')
-rw-r--r-- | libraries/base/Data/Either.hs | 12 | ||||
-rw-r--r-- | libraries/base/Data/Functor/Const.hs | 4 | ||||
-rw-r--r-- | libraries/base/Data/Functor/Identity.hs | 4 | ||||
-rw-r--r-- | libraries/base/Data/Functor/Utils.hs | 36 | ||||
-rw-r--r-- | libraries/base/Data/Monoid.hs | 165 | ||||
-rw-r--r-- | libraries/base/Data/Ord.hs | 1 | ||||
-rw-r--r-- | libraries/base/Data/Proxy.hs | 7 | ||||
-rw-r--r-- | libraries/base/Data/Semigroup.hs | 296 | ||||
-rw-r--r-- | libraries/base/Data/Semigroup/Internal.hs | 258 | ||||
-rw-r--r-- | libraries/base/Data/Semigroup/Internal.hs-boot | 12 | ||||
-rw-r--r-- | libraries/base/Data/Void.hs | 6 | ||||
-rw-r--r-- | libraries/base/GHC/Base.hs | 171 | ||||
-rw-r--r-- | libraries/base/GHC/Base.hs-boot | 10 | ||||
-rw-r--r-- | libraries/base/GHC/Event/Internal.hs | 18 | ||||
-rw-r--r-- | libraries/base/GHC/Real.hs-boot | 7 | ||||
-rw-r--r-- | libraries/base/GHC/ST.hs | 5 | ||||
-rw-r--r-- | libraries/base/Prelude.hs | 3 | ||||
-rw-r--r-- | libraries/base/base.cabal | 1 | ||||
-rw-r--r-- | libraries/base/changelog.md | 6 |
19 files changed, 526 insertions, 496 deletions
diff --git a/libraries/base/Data/Either.hs b/libraries/base/Data/Either.hs index 2469e78511..58a8020034 100644 --- a/libraries/base/Data/Either.hs +++ b/libraries/base/Data/Either.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE Trustworthy #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE StandaloneDeriving #-} @@ -131,6 +132,17 @@ instance Functor (Either a) where fmap _ (Left x) = Left x fmap f (Right y) = Right (f y) +-- | @since 4.9.0.0 +instance Semigroup (Either a b) where + Left _ <> b = b + a <> _ = a +#if !defined(__HADDOCK_VERSION__) + -- workaround https://github.com/haskell/haddock/issues/680 + stimes n x + | n <= 0 = errorWithoutStackTrace "stimes: positive multiplier expected" + | otherwise = x +#endif + -- | @since 3.0 instance Applicative (Either e) where pure = Right diff --git a/libraries/base/Data/Functor/Const.hs b/libraries/base/Data/Functor/Const.hs index 9199b7cf94..8a33e580ad 100644 --- a/libraries/base/Data/Functor/Const.hs +++ b/libraries/base/Data/Functor/Const.hs @@ -38,8 +38,8 @@ import GHC.Show (Show(showsPrec), showParen, showString) -- | The 'Const' functor. newtype Const a b = Const { getConst :: a } deriving ( Bits, Bounded, Enum, Eq, FiniteBits, Floating, Fractional - , Generic, Generic1, Integral, Ix, Monoid, Num, Ord, Real - , RealFrac, RealFloat , Storable) + , Generic, Generic1, Integral, Ix, Semigroup, Monoid, Num, Ord + , Real, RealFrac, RealFloat, Storable) -- | This instance would be equivalent to the derived instances of the -- 'Const' newtype if the 'runConst' field were removed diff --git a/libraries/base/Data/Functor/Identity.hs b/libraries/base/Data/Functor/Identity.hs index 1fe127f310..41c32d0d15 100644 --- a/libraries/base/Data/Functor/Identity.hs +++ b/libraries/base/Data/Functor/Identity.hs @@ -43,7 +43,7 @@ import Data.Functor.Utils ((#.)) import Foreign.Storable (Storable) import GHC.Arr (Ix) import GHC.Base ( Applicative(..), Eq(..), Functor(..), Monad(..) - , Monoid, Ord(..), ($), (.) ) + , Semigroup, Monoid, Ord(..), ($), (.) ) import GHC.Enum (Bounded, Enum) import GHC.Float (Floating, RealFloat) import GHC.Generics (Generic, Generic1) @@ -58,7 +58,7 @@ import GHC.Types (Bool(..)) -- @since 4.8.0.0 newtype Identity a = Identity { runIdentity :: a } deriving ( Bits, Bounded, Enum, Eq, FiniteBits, Floating, Fractional - , Generic, Generic1, Integral, Ix, Monoid, Num, Ord + , Generic, Generic1, Integral, Ix, Semigroup, Monoid, Num, Ord , Real, RealFrac, RealFloat, Storable) -- | This instance would be equivalent to the derived instances of the diff --git a/libraries/base/Data/Functor/Utils.hs b/libraries/base/Data/Functor/Utils.hs index 1bd729bcca..c6c2758c9d 100644 --- a/libraries/base/Data/Functor/Utils.hs +++ b/libraries/base/Data/Functor/Utils.hs @@ -11,7 +11,7 @@ module Data.Functor.Utils where import Data.Coerce (Coercible, coerce) import GHC.Base ( Applicative(..), Functor(..), Maybe(..), Monoid(..), Ord(..) - , ($), otherwise ) + , Semigroup(..), ($), otherwise ) -- We don't expose Max and Min because, as Edward Kmett pointed out to me, -- there are two reasonable ways to define them. One way is to use Maybe, as we @@ -22,27 +22,31 @@ import GHC.Base ( Applicative(..), Functor(..), Maybe(..), Monoid(..), Ord(..) newtype Max a = Max {getMax :: Maybe a} newtype Min a = Min {getMin :: Maybe a} +-- | @since 4.11.0.0 +instance Ord a => Semigroup (Max a) where + {-# INLINE (<>) #-} + m <> Max Nothing = m + Max Nothing <> n = n + (Max m@(Just x)) <> (Max n@(Just y)) + | x >= y = Max m + | otherwise = Max n + -- | @since 4.8.0.0 instance Ord a => Monoid (Max a) where - mempty = Max Nothing + mempty = Max Nothing - {-# INLINE mappend #-} - m `mappend` Max Nothing = m - Max Nothing `mappend` n = n - (Max m@(Just x)) `mappend` (Max n@(Just y)) - | x >= y = Max m - | otherwise = Max n +-- | @since 4.11.0.0 +instance Ord a => Semigroup (Min a) where + {-# INLINE (<>) #-} + m <> Min Nothing = m + Min Nothing <> n = n + (Min m@(Just x)) <> (Min n@(Just y)) + | x <= y = Min m + | otherwise = Min n -- | @since 4.8.0.0 instance Ord a => Monoid (Min a) where - mempty = Min Nothing - - {-# INLINE mappend #-} - m `mappend` Min Nothing = m - Min Nothing `mappend` n = n - (Min m@(Just x)) `mappend` (Min n@(Just y)) - | x <= y = Min m - | otherwise = Min n + mempty = Min Nothing -- left-to-right state transformer newtype StateL s a = StateL { runStateL :: s -> (s, a) } diff --git a/libraries/base/Data/Monoid.hs b/libraries/base/Data/Monoid.hs index 2e8178460f..1284a078ce 100644 --- a/libraries/base/Data/Monoid.hs +++ b/libraries/base/Data/Monoid.hs @@ -43,148 +43,11 @@ module Data.Monoid ( -- Push down the module in the dependency hierarchy. import GHC.Base hiding (Any) -import GHC.Enum -import GHC.Num import GHC.Read import GHC.Show import GHC.Generics -{- --- just for testing -import Data.Maybe -import Test.QuickCheck --- -} - -infixr 6 <> - --- | An infix synonym for 'mappend'. --- --- @since 4.5.0.0 -(<>) :: Monoid m => m -> m -> m -(<>) = mappend -{-# INLINE (<>) #-} - --- Monoid instances. - --- | The dual of a 'Monoid', obtained by swapping the arguments of 'mappend'. --- --- >>> getDual (mappend (Dual "Hello") (Dual "World")) --- "WorldHello" -newtype Dual a = Dual { getDual :: a } - deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1) - --- | @since 2.01 -instance Monoid a => Monoid (Dual a) where - mempty = Dual mempty - Dual x `mappend` Dual y = Dual (y `mappend` x) - --- | @since 4.8.0.0 -instance Functor Dual where - fmap = coerce - --- | @since 4.8.0.0 -instance Applicative Dual where - pure = Dual - (<*>) = coerce - --- | @since 4.8.0.0 -instance Monad Dual where - m >>= k = k (getDual m) - --- | The monoid of endomorphisms under composition. --- --- >>> let computation = Endo ("Hello, " ++) <> Endo (++ "!") --- >>> appEndo computation "Haskell" --- "Hello, Haskell!" -newtype Endo a = Endo { appEndo :: a -> a } - deriving (Generic) - --- | @since 2.01 -instance Monoid (Endo a) where - mempty = Endo id - Endo f `mappend` Endo g = Endo (f . g) - --- | Boolean monoid under conjunction ('&&'). --- --- >>> getAll (All True <> mempty <> All False) --- False --- --- >>> getAll (mconcat (map (\x -> All (even x)) [2,4,6,7,8])) --- False -newtype All = All { getAll :: Bool } - deriving (Eq, Ord, Read, Show, Bounded, Generic) - --- | @since 2.01 -instance Monoid All where - mempty = All True - All x `mappend` All y = All (x && y) - --- | Boolean monoid under disjunction ('||'). --- --- >>> getAny (Any True <> mempty <> Any False) --- True --- --- >>> getAny (mconcat (map (\x -> Any (even x)) [2,4,6,7,8])) --- True -newtype Any = Any { getAny :: Bool } - deriving (Eq, Ord, Read, Show, Bounded, Generic) - --- | @since 2.01 -instance Monoid Any where - mempty = Any False - Any x `mappend` Any y = Any (x || y) - --- | Monoid under addition. --- --- >>> getSum (Sum 1 <> Sum 2 <> mempty) --- 3 -newtype Sum a = Sum { getSum :: a } - deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1, Num) - --- | @since 2.01 -instance Num a => Monoid (Sum a) where - mempty = Sum 0 - mappend = coerce ((+) :: a -> a -> a) --- Sum x `mappend` Sum y = Sum (x + y) - --- | @since 4.8.0.0 -instance Functor Sum where - fmap = coerce - --- | @since 4.8.0.0 -instance Applicative Sum where - pure = Sum - (<*>) = coerce - --- | @since 4.8.0.0 -instance Monad Sum where - m >>= k = k (getSum m) - --- | Monoid under multiplication. --- --- >>> getProduct (Product 3 <> Product 4 <> mempty) --- 12 -newtype Product a = Product { getProduct :: a } - deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1, Num) - --- | @since 2.01 -instance Num a => Monoid (Product a) where - mempty = Product 1 - mappend = coerce ((*) :: a -> a -> a) --- Product x `mappend` Product y = Product (x * y) - --- | @since 4.8.0.0 -instance Functor Product where - fmap = coerce - --- | @since 4.8.0.0 -instance Applicative Product where - pure = Product - (<*>) = coerce - --- | @since 4.8.0.0 -instance Monad Product where - m >>= k = k (getProduct m) +import Data.Semigroup.Internal -- $MaybeExamples -- To implement @find@ or @findLast@ on any 'Foldable': @@ -229,11 +92,15 @@ newtype First a = First { getFirst :: Maybe a } deriving (Eq, Ord, Read, Show, Generic, Generic1, Functor, Applicative, Monad) +-- | @since 4.9.0.0 +instance Semigroup (First a) where + First Nothing <> b = b + a <> _ = a + stimes = stimesIdempotentMonoid + -- | @since 2.01 instance Monoid (First a) where mempty = First Nothing - First Nothing `mappend` r = r - l `mappend` _ = l -- | Maybe monoid returning the rightmost non-Nothing value. -- @@ -246,23 +113,17 @@ newtype Last a = Last { getLast :: Maybe a } deriving (Eq, Ord, Read, Show, Generic, Generic1, Functor, Applicative, Monad) +-- | @since 4.9.0.0 +instance Semigroup (Last a) where + a <> Last Nothing = a + _ <> b = b + stimes = stimesIdempotentMonoid + -- | @since 2.01 instance Monoid (Last a) where mempty = Last Nothing - l `mappend` Last Nothing = l - _ `mappend` r = r --- | Monoid under '<|>'. --- --- @since 4.8.0.0 -newtype Alt f a = Alt {getAlt :: f a} - deriving (Generic, Generic1, Read, Show, Eq, Ord, Num, Enum, - Monad, MonadPlus, Applicative, Alternative, Functor) --- | @since 4.8.0.0 -instance Alternative f => Monoid (Alt f a) where - mempty = Alt empty - mappend = coerce ((<|>) :: f a -> f a -> f a) {- {-------------------------------------------------------------------- diff --git a/libraries/base/Data/Ord.hs b/libraries/base/Data/Ord.hs index 11d6967134..2f5798cca2 100644 --- a/libraries/base/Data/Ord.hs +++ b/libraries/base/Data/Ord.hs @@ -52,6 +52,7 @@ newtype Down a = Down a , Show -- ^ @since 4.7.0.0 , Read -- ^ @since 4.7.0.0 , Num -- ^ @since 4.11.0.0 + , Semigroup -- ^ @since 4.11.0.0 , Monoid -- ^ @since 4.11.0.0 ) diff --git a/libraries/base/Data/Proxy.hs b/libraries/base/Data/Proxy.hs index 2ebb4ab7b5..4f824d0e3c 100644 --- a/libraries/base/Data/Proxy.hs +++ b/libraries/base/Data/Proxy.hs @@ -98,10 +98,15 @@ instance Ix (Proxy s) where unsafeIndex _ _ = 0 unsafeRangeSize _ = 1 +-- | @since 4.9.0.0 +instance Semigroup (Proxy s) where + _ <> _ = Proxy + sconcat _ = Proxy + stimes _ _ = Proxy + -- | @since 4.7.0.0 instance Monoid (Proxy s) where mempty = Proxy - mappend _ _ = Proxy mconcat _ = Proxy -- | @since 4.7.0.0 diff --git a/libraries/base/Data/Semigroup.hs b/libraries/base/Data/Semigroup.hs index 8631b117be..4d06a40a6d 100644 --- a/libraries/base/Data/Semigroup.hs +++ b/libraries/base/Data/Semigroup.hs @@ -48,7 +48,6 @@ module Data.Semigroup ( , Last(..) , WrappedMonoid(..) -- * Re-exported monoids from Data.Monoid - , Monoid(..) , Dual(..) , Endo(..) , All(..) @@ -69,267 +68,31 @@ module Data.Semigroup ( import Prelude hiding (foldr1) +import GHC.Base (Semigroup(..)) + +import Data.Semigroup.Internal + import Control.Applicative import Control.Monad import Control.Monad.Fix -import Control.Monad.ST(ST) import Data.Bifoldable import Data.Bifunctor import Data.Bitraversable import Data.Coerce import Data.Data -import Data.Functor.Identity -import Data.List.NonEmpty import Data.Monoid (All (..), Any (..), Dual (..), Endo (..), Product (..), Sum (..)) -import Data.Monoid (Alt (..)) -import qualified Data.Monoid as Monoid -import Data.Ord (Down(..)) -import Data.Void -#if !defined(mingw32_HOST_OS) -import GHC.Event (Event, Lifetime) -#endif +-- import qualified Data.Monoid as Monoid import GHC.Generics -infixr 6 <> - --- | The class of semigroups (types with an associative binary operation). --- --- @since 4.9.0.0 -class Semigroup a where - -- | An associative operation. - -- - -- @ - -- (a '<>' b) '<>' c = a '<>' (b '<>' c) - -- @ - -- - -- If @a@ is also a 'Monoid' we further require - -- - -- @ - -- ('<>') = 'mappend' - -- @ - (<>) :: a -> a -> a - - default (<>) :: Monoid a => a -> a -> a - (<>) = mappend - - -- | Reduce a non-empty list with @\<\>@ - -- - -- The default definition should be sufficient, but this can be - -- overridden for efficiency. - -- - sconcat :: NonEmpty a -> a - sconcat (a :| as) = go a as where - go b (c:cs) = b <> go c cs - go b [] = b - - -- | Repeat a value @n@ times. - -- - -- Given that this works on a 'Semigroup' it is allowed to fail if - -- you request 0 or fewer repetitions, and the default definition - -- will do so. - -- - -- By making this a member of the class, idempotent semigroups and monoids can - -- upgrade this to execute in /O(1)/ by picking - -- @stimes = stimesIdempotent@ or @stimes = stimesIdempotentMonoid@ - -- respectively. - stimes :: Integral b => b -> a -> a - stimes y0 x0 - | y0 <= 0 = errorWithoutStackTrace "stimes: positive multiplier expected" - | otherwise = f x0 y0 - where - f x y - | even y = f (x <> x) (y `quot` 2) - | y == 1 = x - | otherwise = g (x <> x) (pred y `quot` 2) x - g x y z - | even y = g (x <> x) (y `quot` 2) z - | y == 1 = x <> z - | otherwise = g (x <> x) (pred y `quot` 2) (x <> z) - -- | A generalization of 'Data.List.cycle' to an arbitrary 'Semigroup'. -- May fail to terminate for some values in some semigroups. cycle1 :: Semigroup m => m -> m cycle1 xs = xs' where xs' = xs <> xs' --- | @since 4.9.0.0 -instance Semigroup () where - _ <> _ = () - sconcat _ = () - stimes _ _ = () - --- | @since 4.9.0.0 -instance Semigroup b => Semigroup (a -> b) where - f <> g = \a -> f a <> g a - stimes n f e = stimes n (f e) - --- | @since 4.9.0.0 -instance Semigroup [a] where - (<>) = (++) - stimes n x - | n < 0 = errorWithoutStackTrace "stimes: [], negative multiplier" - | otherwise = rep n - where - rep 0 = [] - rep i = x ++ rep (i - 1) - --- | @since 4.9.0.0 -instance Semigroup a => Semigroup (Maybe a) where - Nothing <> b = b - a <> Nothing = a - Just a <> Just b = Just (a <> b) - stimes _ Nothing = Nothing - stimes n (Just a) = case compare n 0 of - LT -> errorWithoutStackTrace "stimes: Maybe, negative multiplier" - EQ -> Nothing - GT -> Just (stimes n a) - --- | @since 4.9.0.0 -instance Semigroup (Either a b) where - Left _ <> b = b - a <> _ = a - stimes = stimesIdempotent - --- | @since 4.9.0.0 -instance (Semigroup a, Semigroup b) => Semigroup (a, b) where - (a,b) <> (a',b') = (a<>a',b<>b') - stimes n (a,b) = (stimes n a, stimes n b) - --- | @since 4.9.0.0 -instance (Semigroup a, Semigroup b, Semigroup c) => Semigroup (a, b, c) where - (a,b,c) <> (a',b',c') = (a<>a',b<>b',c<>c') - stimes n (a,b,c) = (stimes n a, stimes n b, stimes n c) - --- | @since 4.9.0.0 -instance (Semigroup a, Semigroup b, Semigroup c, Semigroup d) - => Semigroup (a, b, c, d) where - (a,b,c,d) <> (a',b',c',d') = (a<>a',b<>b',c<>c',d<>d') - stimes n (a,b,c,d) = (stimes n a, stimes n b, stimes n c, stimes n d) - --- | @since 4.9.0.0 -instance (Semigroup a, Semigroup b, Semigroup c, Semigroup d, Semigroup e) - => Semigroup (a, b, c, d, e) where - (a,b,c,d,e) <> (a',b',c',d',e') = (a<>a',b<>b',c<>c',d<>d',e<>e') - stimes n (a,b,c,d,e) = - (stimes n a, stimes n b, stimes n c, stimes n d, stimes n e) - --- | @since 4.9.0.0 -instance Semigroup Ordering where - LT <> _ = LT - EQ <> y = y - GT <> _ = GT - stimes = stimesIdempotentMonoid - --- | @since 4.9.0.0 -instance Semigroup a => Semigroup (Dual a) where - Dual a <> Dual b = Dual (b <> a) - stimes n (Dual a) = Dual (stimes n a) - --- | @since 4.9.0.0 -instance Semigroup (Endo a) where - (<>) = coerce ((.) :: (a -> a) -> (a -> a) -> (a -> a)) - stimes = stimesMonoid - --- | @since 4.9.0.0 -instance Semigroup All where - (<>) = coerce (&&) - stimes = stimesIdempotentMonoid - --- | @since 4.9.0.0 -instance Semigroup Any where - (<>) = coerce (||) - stimes = stimesIdempotentMonoid - --- | @since 4.11.0.0 -instance Semigroup a => Semigroup (Down a) where - Down a <> Down b = Down (a <> b) - stimes n (Down a) = Down (stimes n a) - - --- | @since 4.9.0.0 -instance Num a => Semigroup (Sum a) where - (<>) = coerce ((+) :: a -> a -> a) - stimes n (Sum a) = Sum (fromIntegral n * a) - --- | @since 4.9.0.0 -instance Num a => Semigroup (Product a) where - (<>) = coerce ((*) :: a -> a -> a) - stimes n (Product a) = Product (a ^ n) - --- | This is a valid definition of 'stimes' for a 'Monoid'. --- --- Unlike the default definition of 'stimes', it is defined for 0 --- and so it should be preferred where possible. -stimesMonoid :: (Integral b, Monoid a) => b -> a -> a -stimesMonoid n x0 = case compare n 0 of - LT -> errorWithoutStackTrace "stimesMonoid: negative multiplier" - EQ -> mempty - GT -> f x0 n - where - f x y - | even y = f (x `mappend` x) (y `quot` 2) - | y == 1 = x - | otherwise = g (x `mappend` x) (pred y `quot` 2) x - g x y z - | even y = g (x `mappend` x) (y `quot` 2) z - | y == 1 = x `mappend` z - | otherwise = g (x `mappend` x) (pred y `quot` 2) (x `mappend` z) - --- | This is a valid definition of 'stimes' for an idempotent 'Monoid'. --- --- When @mappend x x = x@, this definition should be preferred, because it --- works in /O(1)/ rather than /O(log n)/ -stimesIdempotentMonoid :: (Integral b, Monoid a) => b -> a -> a -stimesIdempotentMonoid n x = case compare n 0 of - LT -> errorWithoutStackTrace "stimesIdempotentMonoid: negative multiplier" - EQ -> mempty - GT -> x - --- | This is a valid definition of 'stimes' for an idempotent 'Semigroup'. --- --- When @x <> x = x@, this definition should be preferred, because it --- works in /O(1)/ rather than /O(log n)/. -stimesIdempotent :: Integral b => b -> a -> a -stimesIdempotent n x - | n <= 0 = errorWithoutStackTrace "stimesIdempotent: positive multiplier expected" - | otherwise = x - --- | @since 4.9.0.0 -instance Semigroup a => Semigroup (Identity a) where - (<>) = coerce ((<>) :: a -> a -> a) - stimes n (Identity a) = Identity (stimes n a) - --- | @since 4.9.0.0 -instance Semigroup a => Semigroup (Const a b) where - (<>) = coerce ((<>) :: a -> a -> a) - stimes n (Const a) = Const (stimes n a) - --- | @since 4.9.0.0 -instance Semigroup (Monoid.First a) where - Monoid.First Nothing <> b = b - a <> _ = a - stimes = stimesIdempotentMonoid - --- | @since 4.9.0.0 -instance Semigroup (Monoid.Last a) where - a <> Monoid.Last Nothing = a - _ <> b = b - stimes = stimesIdempotentMonoid - --- | @since 4.9.0.0 -instance Alternative f => Semigroup (Alt f a) where - (<>) = coerce ((<|>) :: f a -> f a -> f a) - stimes = stimesMonoid - --- | @since 4.9.0.0 -instance Semigroup Void where - a <> _ = a - stimes = stimesIdempotent - --- | @since 4.9.0.0 -instance Semigroup (NonEmpty a) where - (a :| as) <> ~(b :| bs) = a :| (as ++ b : bs) - +-- | This lets you use a difference list of a 'Semigroup' as a 'Monoid'. +diff :: Semigroup m => m -> Endo m +diff = Endo . (<>) newtype Min a = Min { getMin :: a } deriving (Bounded, Eq, Ord, Show, Read, Data, Generic, Generic1) @@ -354,7 +117,6 @@ instance Ord a => Semigroup (Min a) where -- | @since 4.9.0.0 instance (Ord a, Bounded a) => Monoid (Min a) where mempty = maxBound - mappend = (<>) -- | @since 4.9.0.0 instance Functor Min where @@ -417,7 +179,6 @@ instance Ord a => Semigroup (Max a) where -- | @since 4.9.0.0 instance (Ord a, Bounded a) => Monoid (Max a) where mempty = minBound - mappend = (<>) -- | @since 4.9.0.0 instance Functor Max where @@ -498,7 +259,7 @@ instance Bifunctor Arg where -- | @since 4.10.0.0 instance Bifoldable Arg where - bifoldMap f g (Arg a b) = f a `mappend` g b + bifoldMap f g (Arg a b) = f a <> g b -- | @since 4.10.0.0 instance Bitraversable Arg where @@ -606,6 +367,9 @@ instance MonadFix Last where mfix f = fix (f . getLast) -- | Provide a Semigroup for an arbitrary Monoid. +-- +-- __NOTE__: This is not needed anymore since 'Semigroup' became a superclass of +-- 'Monoid' in /base-4.11/ and this newtype be deprecated at some point in the future. newtype WrappedMonoid m = WrapMonoid { unwrapMonoid :: m } deriving (Bounded, Eq, Ord, Show, Read, Data, Generic, Generic1) @@ -616,7 +380,6 @@ instance Monoid m => Semigroup (WrappedMonoid m) where -- | @since 4.9.0.0 instance Monoid m => Monoid (WrappedMonoid m) where mempty = WrapMonoid mempty - mappend = (<>) -- | @since 4.9.0.0 instance Enum a => Enum (WrappedMonoid a) where @@ -700,44 +463,15 @@ option n j (Option m) = maybe n j m -- | @since 4.9.0.0 instance Semigroup a => Semigroup (Option a) where (<>) = coerce ((<>) :: Maybe a -> Maybe a -> Maybe a) - +#if !defined(__HADDOCK_VERSION__) + -- workaround https://github.com/haskell/haddock/issues/680 stimes _ (Option Nothing) = Option Nothing stimes n (Option (Just a)) = case compare n 0 of LT -> errorWithoutStackTrace "stimes: Option, negative multiplier" EQ -> Option Nothing GT -> Option (Just (stimes n a)) +#endif -- | @since 4.9.0.0 instance Semigroup a => Monoid (Option a) where mempty = Option Nothing - mappend = (<>) - --- | This lets you use a difference list of a 'Semigroup' as a 'Monoid'. -diff :: Semigroup m => m -> Endo m -diff = Endo . (<>) - --- | @since 4.9.0.0 -instance Semigroup (Proxy s) where - _ <> _ = Proxy - sconcat _ = Proxy - stimes _ _ = Proxy - --- | @since 4.10.0.0 -instance Semigroup a => Semigroup (IO a) where - (<>) = liftA2 (<>) - --- | @since 4.11.0.0 -instance Semigroup a => Semigroup (ST s a) where - (<>) = liftA2 (<>) - -#if !defined(mingw32_HOST_OS) --- | @since 4.10.0.0 -instance Semigroup Event where - (<>) = mappend - stimes = stimesMonoid - --- | @since 4.10.0.0 -instance Semigroup Lifetime where - (<>) = mappend - stimes = stimesMonoid -#endif diff --git a/libraries/base/Data/Semigroup/Internal.hs b/libraries/base/Data/Semigroup/Internal.hs new file mode 100644 index 0000000000..3cdf54bb33 --- /dev/null +++ b/libraries/base/Data/Semigroup/Internal.hs @@ -0,0 +1,258 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE ScopedTypeVariables #-} + +-- | Auxilary definitions for 'Semigroup' +-- +-- This module provides some @newtype@ wrappers and helpers which are +-- reexported from the "Data.Semigroup" module or imported directly +-- by some other modules. +-- +-- This module also provides internal definitions related to the +-- 'Semigroup' class some. +-- +-- This module exists mostly to simplify or workaround import-graph +-- issues; there is also a .hs-boot file to allow "GHC.Base" and other +-- modules to import method default implementations for 'stimes' +-- +-- @since 4.11.0.0 +module Data.Semigroup.Internal where + +import GHC.Base hiding (Any) +import GHC.Enum +import GHC.Num +import GHC.Read +import GHC.Show +import GHC.Generics +import GHC.Real + +-- | This is a valid definition of 'stimes' for an idempotent 'Semigroup'. +-- +-- When @x <> x = x@, this definition should be preferred, because it +-- works in /O(1)/ rather than /O(log n)/. +stimesIdempotent :: Integral b => b -> a -> a +stimesIdempotent n x + | n <= 0 = errorWithoutStackTrace "stimesIdempotent: positive multiplier expected" + | otherwise = x + +-- | This is a valid definition of 'stimes' for an idempotent 'Monoid'. +-- +-- When @mappend x x = x@, this definition should be preferred, because it +-- works in /O(1)/ rather than /O(log n)/ +stimesIdempotentMonoid :: (Integral b, Monoid a) => b -> a -> a +stimesIdempotentMonoid n x = case compare n 0 of + LT -> errorWithoutStackTrace "stimesIdempotentMonoid: negative multiplier" + EQ -> mempty + GT -> x + +-- | This is a valid definition of 'stimes' for a 'Monoid'. +-- +-- Unlike the default definition of 'stimes', it is defined for 0 +-- and so it should be preferred where possible. +stimesMonoid :: (Integral b, Monoid a) => b -> a -> a +stimesMonoid n x0 = case compare n 0 of + LT -> errorWithoutStackTrace "stimesMonoid: negative multiplier" + EQ -> mempty + GT -> f x0 n + where + f x y + | even y = f (x `mappend` x) (y `quot` 2) + | y == 1 = x + | otherwise = g (x `mappend` x) (pred y `quot` 2) x + g x y z + | even y = g (x `mappend` x) (y `quot` 2) z + | y == 1 = x `mappend` z + | otherwise = g (x `mappend` x) (pred y `quot` 2) (x `mappend` z) + +-- this is used by the class definitionin GHC.Base; +-- it lives here to avoid cycles +stimesDefault :: (Integral b, Semigroup a) => b -> a -> a +stimesDefault y0 x0 + | y0 <= 0 = errorWithoutStackTrace "stimes: positive multiplier expected" + | otherwise = f x0 y0 + where + f x y + | even y = f (x <> x) (y `quot` 2) + | y == 1 = x + | otherwise = g (x <> x) (pred y `quot` 2) x + g x y z + | even y = g (x <> x) (y `quot` 2) z + | y == 1 = x <> z + | otherwise = g (x <> x) (pred y `quot` 2) (x <> z) + +stimesMaybe :: (Integral b, Semigroup a) => b -> Maybe a -> Maybe a +stimesMaybe _ Nothing = Nothing +stimesMaybe n (Just a) = case compare n 0 of + LT -> errorWithoutStackTrace "stimes: Maybe, negative multiplier" + EQ -> Nothing + GT -> Just (stimes n a) + +stimesList :: Integral b => b -> [a] -> [a] +stimesList n x + | n < 0 = errorWithoutStackTrace "stimes: [], negative multiplier" + | otherwise = rep n + where + rep 0 = [] + rep i = x ++ rep (i - 1) + +-- | The dual of a 'Monoid', obtained by swapping the arguments of 'mappend'. +-- +-- >>> getDual (mappend (Dual "Hello") (Dual "World")) +-- "WorldHello" +newtype Dual a = Dual { getDual :: a } + deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1) + +-- | @since 4.9.0.0 +instance Semigroup a => Semigroup (Dual a) where + Dual a <> Dual b = Dual (b <> a) + stimes n (Dual a) = Dual (stimes n a) + +-- | @since 2.01 +instance Monoid a => Monoid (Dual a) where + mempty = Dual mempty + +-- | @since 4.8.0.0 +instance Functor Dual where + fmap = coerce + +-- | @since 4.8.0.0 +instance Applicative Dual where + pure = Dual + (<*>) = coerce + +-- | @since 4.8.0.0 +instance Monad Dual where + m >>= k = k (getDual m) + +-- | The monoid of endomorphisms under composition. +-- +-- >>> let computation = Endo ("Hello, " ++) <> Endo (++ "!") +-- >>> appEndo computation "Haskell" +-- "Hello, Haskell!" +newtype Endo a = Endo { appEndo :: a -> a } + deriving (Generic) + +-- | @since 4.9.0.0 +instance Semigroup (Endo a) where + (<>) = coerce ((.) :: (a -> a) -> (a -> a) -> (a -> a)) + stimes = stimesMonoid + +-- | @since 2.01 +instance Monoid (Endo a) where + mempty = Endo id + +-- | Boolean monoid under conjunction ('&&'). +-- +-- >>> getAll (All True <> mempty <> All False) +-- False +-- +-- >>> getAll (mconcat (map (\x -> All (even x)) [2,4,6,7,8])) +-- False +newtype All = All { getAll :: Bool } + deriving (Eq, Ord, Read, Show, Bounded, Generic) + +-- | @since 4.9.0.0 +instance Semigroup All where + (<>) = coerce (&&) + stimes = stimesIdempotentMonoid + +-- | @since 2.01 +instance Monoid All where + mempty = All True + +-- | Boolean monoid under disjunction ('||'). +-- +-- >>> getAny (Any True <> mempty <> Any False) +-- True +-- +-- >>> getAny (mconcat (map (\x -> Any (even x)) [2,4,6,7,8])) +-- True +newtype Any = Any { getAny :: Bool } + deriving (Eq, Ord, Read, Show, Bounded, Generic) + +-- | @since 4.9.0.0 +instance Semigroup Any where + (<>) = coerce (||) + stimes = stimesIdempotentMonoid + +-- | @since 2.01 +instance Monoid Any where + mempty = Any False + +-- | Monoid under addition. +-- +-- >>> getSum (Sum 1 <> Sum 2 <> mempty) +-- 3 +newtype Sum a = Sum { getSum :: a } + deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1, Num) + +-- | @since 4.9.0.0 +instance Num a => Semigroup (Sum a) where + (<>) = coerce ((+) :: a -> a -> a) + stimes n (Sum a) = Sum (fromIntegral n * a) + +-- | @since 2.01 +instance Num a => Monoid (Sum a) where + mempty = Sum 0 + +-- | @since 4.8.0.0 +instance Functor Sum where + fmap = coerce + +-- | @since 4.8.0.0 +instance Applicative Sum where + pure = Sum + (<*>) = coerce + +-- | @since 4.8.0.0 +instance Monad Sum where + m >>= k = k (getSum m) + +-- | Monoid under multiplication. +-- +-- >>> getProduct (Product 3 <> Product 4 <> mempty) +-- 12 +newtype Product a = Product { getProduct :: a } + deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1, Num) + +-- | @since 4.9.0.0 +instance Num a => Semigroup (Product a) where + (<>) = coerce ((*) :: a -> a -> a) + stimes n (Product a) = Product (a ^ n) + + +-- | @since 2.01 +instance Num a => Monoid (Product a) where + mempty = Product 1 + +-- | @since 4.8.0.0 +instance Functor Product where + fmap = coerce + +-- | @since 4.8.0.0 +instance Applicative Product where + pure = Product + (<*>) = coerce + +-- | @since 4.8.0.0 +instance Monad Product where + m >>= k = k (getProduct m) + + +-- | Monoid under '<|>'. +-- +-- @since 4.8.0.0 +newtype Alt f a = Alt {getAlt :: f a} + deriving (Generic, Generic1, Read, Show, Eq, Ord, Num, Enum, + Monad, MonadPlus, Applicative, Alternative, Functor) + +-- | @since 4.9.0.0 +instance Alternative f => Semigroup (Alt f a) where + (<>) = coerce ((<|>) :: f a -> f a -> f a) + stimes = stimesMonoid + +-- | @since 4.8.0.0 +instance Alternative f => Monoid (Alt f a) where + mempty = Alt empty diff --git a/libraries/base/Data/Semigroup/Internal.hs-boot b/libraries/base/Data/Semigroup/Internal.hs-boot new file mode 100644 index 0000000000..645a088eb9 --- /dev/null +++ b/libraries/base/Data/Semigroup/Internal.hs-boot @@ -0,0 +1,12 @@ +{-# LANGUAGE NoImplicitPrelude #-} + +module Data.Semigroup.Internal where + +import {-# SOURCE #-} GHC.Real (Integral) +import {-# SOURCE #-} GHC.Base (Semigroup,Monoid,Maybe) + +stimesIdempotentMonoid :: (Integral b, Monoid a) => b -> a -> a + +stimesDefault :: (Integral b, Semigroup a) => b -> a -> a +stimesMaybe :: (Integral b, Semigroup a) => b -> Maybe a -> Maybe a +stimesList :: Integral b => b -> [a] -> [a] diff --git a/libraries/base/Data/Void.hs b/libraries/base/Data/Void.hs index d7fa1799b3..ed3cfbc330 100644 --- a/libraries/base/Data/Void.hs +++ b/libraries/base/Data/Void.hs @@ -28,6 +28,7 @@ import Control.Exception import Data.Data import Data.Ix import GHC.Generics +import Data.Semigroup (Semigroup(..), stimesIdempotent) -- | Uninhabited data type -- @@ -64,6 +65,11 @@ instance Ix Void where -- | @since 4.8.0.0 instance Exception Void +-- | @since 4.9.0.0 +instance Semigroup Void where + a <> _ = a + stimes = stimesIdempotent + -- | Since 'Void' values logically don't exist, this witnesses the -- logical reasoning tool of \"ex falso quodlibet\". -- diff --git a/libraries/base/GHC/Base.hs b/libraries/base/GHC/Base.hs index 96f2d641bd..82b99a88c2 100644 --- a/libraries/base/GHC/Base.hs +++ b/libraries/base/GHC/Base.hs @@ -129,6 +129,14 @@ import {-# SOURCE #-} GHC.IO (failIO,mplusIO) import GHC.Tuple () -- Note [Depend on GHC.Tuple] import GHC.Integer () -- Note [Depend on GHC.Integer] +-- for 'class Semigroup' +import {-# SOURCE #-} GHC.Real (Integral) +import {-# SOURCE #-} Data.Semigroup.Internal ( stimesDefault + , stimesMaybe + , stimesList + , stimesIdempotentMonoid + ) + infixr 9 . infixr 5 ++ infixl 4 <$ @@ -204,16 +212,53 @@ foldr = errorWithoutStackTrace "urk" data Maybe a = Nothing | Just a deriving (Eq, Ord) +infixr 6 <> + +-- | The class of semigroups (types with an associative binary operation). +-- +-- Instances should satisfy the associativity law: +-- +-- * @x '<>' (y '<>' z) = (x '<>' y) '<>' z@ +-- +-- @since 4.9.0.0 +class Semigroup a where + -- | An associative operation. + (<>) :: a -> a -> a + + -- | Reduce a non-empty list with @\<\>@ + -- + -- The default definition should be sufficient, but this can be + -- overridden for efficiency. + -- + sconcat :: NonEmpty a -> a + sconcat (a :| as) = go a as where + go b (c:cs) = b <> go c cs + go b [] = b + + -- | Repeat a value @n@ times. + -- + -- Given that this works on a 'Semigroup' it is allowed to fail if + -- you request 0 or fewer repetitions, and the default definition + -- will do so. + -- + -- By making this a member of the class, idempotent semigroups + -- and monoids can upgrade this to execute in /O(1)/ by + -- picking @stimes = 'stimesIdempotent'@ or @stimes = + -- 'stimesIdempotentMonoid'@ respectively. + stimes :: Integral b => b -> a -> a + stimes = stimesDefault + + -- | The class of monoids (types with an associative binary operation that -- has an identity). Instances should satisfy the following laws: -- --- * @'mappend' 'mempty' x = x@ +-- * @x '<>' 'mempty' = x@ -- --- * @'mappend' x 'mempty' = x@ +-- * @'mempty' '<>' x = x@ -- --- * @'mappend' x ('mappend' y z) = 'mappend' ('mappend' x y) z@ +-- * @x '<>' (y '<>' z) = (x '<>' y) '<>' z@ ('Semigroup' law) -- --- * @'mconcat' = 'foldr' 'mappend' 'mempty'@ +-- * @'mconcat' = 'foldr' '(<>)' 'mempty'@ -- -- The method names refer to the monoid of lists under concatenation, -- but there are many other instances. @@ -222,27 +267,39 @@ data Maybe a = Nothing | Just a -- e.g. both addition and multiplication on numbers. -- In such cases we often define @newtype@s and make those instances -- of 'Monoid', e.g. 'Sum' and 'Product'. - -class Monoid a where +-- +-- __NOTE__: 'Semigroup' is a superclass of 'Monoid' since /base-4.11.0.0/. +class Semigroup a => Monoid a where + -- | Identity of 'mappend' mempty :: a - -- ^ Identity of 'mappend' + + -- | An associative operation + -- + -- __NOTE__: This method is redundant and has the default + -- implementation @'mappend' = '(<>)'@ since /base-4.11.0.0/. mappend :: a -> a -> a - -- ^ An associative operation - mconcat :: [a] -> a + mappend = (<>) + {-# INLINE mappend #-} - -- ^ Fold a list using the monoid. + -- | Fold a list using the monoid. + -- -- For most types, the default definition for 'mconcat' will be -- used, but the function is included in the class definition so -- that an optimized version can be provided for specific types. - + mconcat :: [a] -> a mconcat = foldr mappend mempty +-- | @since 4.9.0.0 +instance Semigroup [a] where + (<>) = (++) + {-# INLINE (<>) #-} + + stimes = stimesList + -- | @since 2.01 instance Monoid [a] where {-# INLINE mempty #-} mempty = [] - {-# INLINE mappend #-} - mappend = (++) {-# INLINE mconcat #-} mconcat xss = [x | xs <- xss, x <- xs] -- See Note: [List comprehensions and inlining] @@ -266,52 +323,92 @@ needed to make foldr/build forms efficient are turned off, we'll get reasonably efficient translations anyway. -} +-- | @since 4.9.0.0 +instance Semigroup (NonEmpty a) where + (a :| as) <> ~(b :| bs) = a :| (as ++ b : bs) + +-- | @since 4.9.0.0 +instance Semigroup b => Semigroup (a -> b) where + f <> g = \x -> f x <> g x + stimes n f e = stimes n (f e) + -- | @since 2.01 instance Monoid b => Monoid (a -> b) where mempty _ = mempty - mappend f g x = f x `mappend` g x + +-- | @since 4.9.0.0 +instance Semigroup () where + _ <> _ = () + sconcat _ = () + stimes _ _ = () -- | @since 2.01 instance Monoid () where -- Should it be strict? mempty = () - _ `mappend` _ = () mconcat _ = () +-- | @since 4.9.0.0 +instance (Semigroup a, Semigroup b) => Semigroup (a, b) where + (a,b) <> (a',b') = (a<>a',b<>b') + stimes n (a,b) = (stimes n a, stimes n b) + -- | @since 2.01 instance (Monoid a, Monoid b) => Monoid (a,b) where mempty = (mempty, mempty) - (a1,b1) `mappend` (a2,b2) = - (a1 `mappend` a2, b1 `mappend` b2) + +-- | @since 4.9.0.0 +instance (Semigroup a, Semigroup b, Semigroup c) => Semigroup (a, b, c) where + (a,b,c) <> (a',b',c') = (a<>a',b<>b',c<>c') + stimes n (a,b,c) = (stimes n a, stimes n b, stimes n c) -- | @since 2.01 instance (Monoid a, Monoid b, Monoid c) => Monoid (a,b,c) where mempty = (mempty, mempty, mempty) - (a1,b1,c1) `mappend` (a2,b2,c2) = - (a1 `mappend` a2, b1 `mappend` b2, c1 `mappend` c2) + +-- | @since 4.9.0.0 +instance (Semigroup a, Semigroup b, Semigroup c, Semigroup d) + => Semigroup (a, b, c, d) where + (a,b,c,d) <> (a',b',c',d') = (a<>a',b<>b',c<>c',d<>d') + stimes n (a,b,c,d) = (stimes n a, stimes n b, stimes n c, stimes n d) -- | @since 2.01 instance (Monoid a, Monoid b, Monoid c, Monoid d) => Monoid (a,b,c,d) where mempty = (mempty, mempty, mempty, mempty) - (a1,b1,c1,d1) `mappend` (a2,b2,c2,d2) = - (a1 `mappend` a2, b1 `mappend` b2, - c1 `mappend` c2, d1 `mappend` d2) + +-- | @since 4.9.0.0 +instance (Semigroup a, Semigroup b, Semigroup c, Semigroup d, Semigroup e) + => Semigroup (a, b, c, d, e) where + (a,b,c,d,e) <> (a',b',c',d',e') = (a<>a',b<>b',c<>c',d<>d',e<>e') + stimes n (a,b,c,d,e) = + (stimes n a, stimes n b, stimes n c, stimes n d, stimes n e) -- | @since 2.01 instance (Monoid a, Monoid b, Monoid c, Monoid d, Monoid e) => Monoid (a,b,c,d,e) where mempty = (mempty, mempty, mempty, mempty, mempty) - (a1,b1,c1,d1,e1) `mappend` (a2,b2,c2,d2,e2) = - (a1 `mappend` a2, b1 `mappend` b2, c1 `mappend` c2, - d1 `mappend` d2, e1 `mappend` e2) + + +-- | @since 4.9.0.0 +instance Semigroup Ordering where + LT <> _ = LT + EQ <> y = y + GT <> _ = GT + + stimes = stimesIdempotentMonoid -- lexicographical ordering -- | @since 2.01 instance Monoid Ordering where - mempty = EQ - LT `mappend` _ = LT - EQ `mappend` y = y - GT `mappend` _ = GT + mempty = EQ + +-- | @since 4.9.0.0 +instance Semigroup a => Semigroup (Maybe a) where + Nothing <> b = b + a <> Nothing = a + Just a <> Just b = Just (a <> b) + + stimes = stimesMaybe -- | Lift a semigroup into 'Maybe' forming a 'Monoid' according to -- <http://en.wikipedia.org/wiki/Monoid>: \"Any semigroup @S@ may be @@ -322,10 +419,7 @@ instance Monoid Ordering where -- -- @since 2.01 instance Monoid a => Monoid (Maybe a) where - mempty = Nothing - Nothing `mappend` m = m - m `mappend` Nothing = m - Just m1 `mappend` Just m2 = Just (m1 `mappend` m2) + mempty = Nothing -- | For tuples, the 'Monoid' constraint on @a@ determines -- how the first values merge. @@ -337,17 +431,20 @@ instance Monoid a => Monoid (Maybe a) where -- @since 2.01 instance Monoid a => Applicative ((,) a) where pure x = (mempty, x) - (u, f) <*> (v, x) = (u `mappend` v, f x) - liftA2 f (u, x) (v, y) = (u `mappend` v, f x y) + (u, f) <*> (v, x) = (u <> v, f x) + liftA2 f (u, x) (v, y) = (u <> v, f x y) -- | @since 4.9.0.0 instance Monoid a => Monad ((,) a) where - (u, a) >>= k = case k a of (v, b) -> (u `mappend` v, b) + (u, a) >>= k = case k a of (v, b) -> (u <> v, b) + +-- | @since 4.10.0.0 +instance Semigroup a => Semigroup (IO a) where + (<>) = liftA2 (<>) -- | @since 4.9.0.0 instance Monoid a => Monoid (IO a) where mempty = pure mempty - mappend = liftA2 mappend {- | The 'Functor' class is used for types that can be mapped over. Instances of 'Functor' should satisfy the following laws: diff --git a/libraries/base/GHC/Base.hs-boot b/libraries/base/GHC/Base.hs-boot new file mode 100644 index 0000000000..ca85b49147 --- /dev/null +++ b/libraries/base/GHC/Base.hs-boot @@ -0,0 +1,10 @@ +{-# LANGUAGE NoImplicitPrelude #-} + +module GHC.Base where + +import GHC.Types () + +class Semigroup a +class Monoid a + +data Maybe a = Nothing | Just a diff --git a/libraries/base/GHC/Event/Internal.hs b/libraries/base/GHC/Event/Internal.hs index 9b8230c032..b7befdda25 100644 --- a/libraries/base/GHC/Event/Internal.hs +++ b/libraries/base/GHC/Event/Internal.hs @@ -36,6 +36,7 @@ import GHC.Base import GHC.Word (Word64) import GHC.Num (Num(..)) import GHC.Show (Show(..)) +import Data.Semigroup.Internal (stimesMonoid) -- | An I\/O event. newtype Event = Event Int @@ -72,10 +73,14 @@ instance Show Event where where ev `so` disp | e `eventIs` ev = disp | otherwise = "" +-- | @since 4.10.0.0 +instance Semigroup Event where + (<>) = evtCombine + stimes = stimesMonoid + -- | @since 4.3.1.0 instance Monoid Event where mempty = evtNothing - mappend = evtCombine mconcat = evtConcat evtCombine :: Event -> Event -> Event @@ -100,12 +105,16 @@ elSupremum OneShot OneShot = OneShot elSupremum _ _ = MultiShot {-# INLINE elSupremum #-} +-- | @since 4.10.0.0 +instance Semigroup Lifetime where + (<>) = elSupremum + stimes = stimesMonoid + -- | @mappend@ takes the longer of two lifetimes. -- -- @since 4.8.0.0 instance Monoid Lifetime where mempty = OneShot - mappend = elSupremum -- | A pair of an event and lifetime -- @@ -114,10 +123,13 @@ instance Monoid Lifetime where newtype EventLifetime = EL Int deriving (Show, Eq) +-- | @since 4.11.0.0 +instance Semigroup EventLifetime where + EL a <> EL b = EL (a .|. b) + -- | @since 4.8.0.0 instance Monoid EventLifetime where mempty = EL 0 - EL a `mappend` EL b = EL (a .|. b) eventLifetime :: Event -> Lifetime -> EventLifetime eventLifetime (Event e) l = EL (e .|. lifetimeBit l) diff --git a/libraries/base/GHC/Real.hs-boot b/libraries/base/GHC/Real.hs-boot new file mode 100644 index 0000000000..b462c1c299 --- /dev/null +++ b/libraries/base/GHC/Real.hs-boot @@ -0,0 +1,7 @@ +{-# LANGUAGE NoImplicitPrelude #-} + +module GHC.Real where + +import GHC.Types () + +class Integral a diff --git a/libraries/base/GHC/ST.hs b/libraries/base/GHC/ST.hs index a245b9fc50..9f8bb6489f 100644 --- a/libraries/base/GHC/ST.hs +++ b/libraries/base/GHC/ST.hs @@ -78,9 +78,12 @@ instance Monad (ST s) where (k2 new_s) }}) -- | @since 4.11.0.0 +instance Semigroup a => Semigroup (ST s a) where + (<>) = liftA2 (<>) + +-- | @since 4.11.0.0 instance Monoid a => Monoid (ST s a) where mempty = pure mempty - mappend = liftA2 mappend data STret s a = STret (State# s) a diff --git a/libraries/base/Prelude.hs b/libraries/base/Prelude.hs index 158cc0a8ff..75a0d5341d 100644 --- a/libraries/base/Prelude.hs +++ b/libraries/base/Prelude.hs @@ -66,7 +66,8 @@ module Prelude ( subtract, even, odd, gcd, lcm, (^), (^^), fromIntegral, realToFrac, - -- ** Monoids + -- ** Semigroups and Monoids + Semigroup, -- TODO: export (<>) Monoid(mempty, mappend, mconcat), -- ** Monads and functors diff --git a/libraries/base/base.cabal b/libraries/base/base.cabal index 4bbe2f2d51..df5efa8d7c 100644 --- a/libraries/base/base.cabal +++ b/libraries/base/base.cabal @@ -317,6 +317,7 @@ Library Control.Monad.ST.Lazy.Imp Data.Functor.Utils Data.OldList + Data.Semigroup.Internal Data.Typeable.Internal Foreign.ForeignPtr.Imp GHC.StaticPtr.Internal diff --git a/libraries/base/changelog.md b/libraries/base/changelog.md index a8915cbbeb..b9b1756c36 100644 --- a/libraries/base/changelog.md +++ b/libraries/base/changelog.md @@ -8,6 +8,12 @@ * Add instances `Num`, `Functor`, `Applicative`, `Monad`, `Semigroup` and `Monoid` for `Data.Ord.Down` (#13097). + * Add `Semigroup` instance for `EventLifetime`. + + * Make `Semigroup` a superclass of `Monoid`; + export `Semigroup` from `Prelude`; remove `Monoid` reexport + from `Data.Semigroup` (#14191). + * Add `infixl 9 !!` declaration for `Data.List.NonEmpty.!!` * Add `<&>` operator to `Data.Functor` (#14029) |