|
|
# Semigroup (as superclass of) Monoid Proposal
|
|
|
|
|
|
|
|
|
|
|
|
THIS DESCRIPTION IS STILL WORK IN PROGRESS
|
|
|
|
|
|
|
|
|
Please comment on [ ghc:\#10365](https://ghc.haskell.org/intertrac/%2310365) or [ ghc:\#14191](https://ghc.haskell.org/intertrac/%2314191) if you notice some show-stopper issue
|
|
|
|
|
|
Please comment on \#10365 if you notice some show-stopper issue
|
|
|
|
|
|
|
|
|
|
|
|
Introducing `Semigroup` as a superclass of `Monoid` has been proposed several times (in reverse chronological order):
|
|
|
|
|
|
|
|
|
- [ http://thread.gmane.org/gmane.comp.lang.haskell.libraries/24494](http://thread.gmane.org/gmane.comp.lang.haskell.libraries/24494)
|
|
|
- [ http://thread.gmane.org/gmane.comp.lang.haskell.libraries/19649](http://thread.gmane.org/gmane.comp.lang.haskell.libraries/19649)
|
|
|
- TODO …
|
... | ... | @@ -16,112 +20,98 @@ Introducing `Semigroup` as a superclass of `Monoid` has been proposed several ti |
|
|
## Final API
|
|
|
|
|
|
|
|
|
|
|
|
The final API (suitable for Haskell Report inclusion) we want to end up with is
|
|
|
|
|
|
```
|
|
|
modulePrelude(Semigroup((<>)),Monoid(mempty,mconcat)-- …)where-- …
|
|
|
```
|
|
|
|
|
|
```
|
|
|
moduleData.SemigroupwhereclassSemigroup a where(<>):: a -> a -> a
|
|
|
module Data.Semigroup where
|
|
|
|
|
|
class Semigroup a where
|
|
|
(<>) :: a -> a -> a
|
|
|
|
|
|
-- not (re)exported from Prelude
|
|
|
sconcat ::NonEmpty a -> a
|
|
|
sconcat (a :| as)= go a as
|
|
|
sconcat :: NonEmpty a -> a
|
|
|
sconcat (a :| as) = go a as
|
|
|
where
|
|
|
go b (c:cs)= b <> go c cs
|
|
|
go b []= b
|
|
|
go b (c:cs) = b <> go c cs
|
|
|
go b [] = b
|
|
|
|
|
|
-- GHC extension, not needed for Haskell Report-- & not (re)exported from Prelude
|
|
|
stimes ::Integral b => b -> a -> a
|
|
|
stimes y0 x0 ={- default impl -}
|
|
|
-- GHC extension, not needed for Haskell Report
|
|
|
stimes :: Integral b => b -> a -> a
|
|
|
stimes y0 x0 = {- default impl -}
|
|
|
```
|
|
|
|
|
|
```
|
|
|
moduleData.MonoidwhereclassSemigroup a =>Monoid a where
|
|
|
module Data.Monoid where
|
|
|
|
|
|
class Semigroup a => Monoid a where
|
|
|
mempty :: a
|
|
|
|
|
|
mconcat ::[a]-> a
|
|
|
mconcat :: [a] -> a
|
|
|
mconcat = foldr (<>) mempty
|
|
|
|
|
|
-- GHC extension, not needed for Haskell Report-- & not (re)exported from Prelude
|
|
|
mtimes ::Integral b => b -> a -> a
|
|
|
mtimes y0 x0 ={- default impl -}-- GHC Extension: Legacy alias not needed for Haskell Reportmappend::Semigroup a => a -> a -> a
|
|
|
mappend=(<>)
|
|
|
-- GHC extension, not needed for Haskell Report
|
|
|
mtimes :: Integral b => b -> a -> a
|
|
|
mtimes y0 x0 = {- default impl -}
|
|
|
|
|
|
-- GHC Extension: Legacy alias not needed for Haskell Report
|
|
|
mappend :: Semigroup a => a -> a -> a
|
|
|
mappend = (<>)
|
|
|
```
|
|
|
|
|
|
## Migration plan
|
|
|
|
|
|
### Phase 1 (GHC 8.0) [ ghc:\#10365](https://ghc.haskell.org/intertrac/%2310365)
|
|
|
|
|
|
### Phase 1 (GHC 8.0) \#10365
|
|
|
|
|
|
|
|
|
- Move `Data.Semigroup` & `Data.List.NonEmpty` from `semigroups-0.18` to `base`.
|
|
|
|
|
|
- (maybe) Implement a warning about definitions of an operator named `(<>)` that indicate it will be coming into Prelude in 8.2. We should warn about missing Semigroup instances at any use site of `(<>)` as they'll break in phase 2.
|
|
|
- (maybe) Implement a warning about definitions of an operator named `(<>)` that indicate it will be coming into Prelude in 8.2. We should warn about missing Semigroup instances at any use site of `(<>)` as they'll break in 8.2.
|
|
|
|
|
|
### Phase 2a
|
|
|
|
|
|
### Phase 2a (GHC 8.4) [ ghc:\#14191](https://ghc.haskell.org/intertrac/%2314191)
|
|
|
|
|
|
- move `Semigroup` class into prelude in anticipation of it becoming a superclass of `Monoid`
|
|
|
|
|
|
### Phase 2b (GHC 8.4) [ ghc:\#14191](https://ghc.haskell.org/intertrac/%2314191)
|
|
|
### Phase 2b (either merge with 2a or with 3)
|
|
|
|
|
|
|
|
|
- Make `Semigroup` a superclass of `Monoid`
|
|
|
|
|
|
### Phase 3
|
|
|
|
|
|
|
|
|
- Deprecate manual definitions of `mappend` (c.f. "Monad of no `return` Proposal")
|
|
|
- encourage overriding the current default-implementation of `(<>)` via `MINIMAL` pragma
|
|
|
|
|
|
### Phase 4
|
|
|
|
|
|
|
|
|
- Move the now deprecated `mappend` method out of the `Monoid` class, and possibly turn `mappend` into a legacy top-level binding (c.f. "Monad of no `return` Proposal")
|
|
|
|
|
|
## Writing compatible code
|
|
|
|
|
|
### Recommended Variant
|
|
|
|
|
|
|
|
|
The code below is expected to be `-Wcompat -Wall` clean
|
|
|
(see also [ https://groups.google.com/forum/\#!msg/haskell-core-libraries/PyxpE2ebS9Q/Ni0ywo_GCgAJ](https://groups.google.com/forum/#!msg/haskell-core-libraries/PyxpE2ebS9Q/Ni0ywo_GCgAJ))
|
|
|
|
|
|
```
|
|
|
importData.Semigroupas Sem
|
|
|
-- base >= 4.8: `Monoid` class is exported via `Prelude`-- base < 4.11: re-exports `Monoid` class & common newtype wrappers-- base >= 4.11: doesn't reexport `Monoid` class anymoreinstanceSem.SemigroupFoowhere(<>)=…instanceMonoidFoowhere
|
|
|
mempty =…#if!(MIN_VERSION_base(4,11,0))-- this is redundant starting with base-4.11 / GHC 8.4-- if you want to avoid CPP, you can define `mappend = (<>)` unconditionally
|
|
|
mappend =(<>)#endif
|
|
|
```
|
|
|
import Data.Semigroup -- re-exports Data.Monoid (w/ Semigroup((<>)))
|
|
|
|
|
|
instance Semigroup Foo where
|
|
|
(<>) = …
|
|
|
|
|
|
If you need compatiblity with GHC prior to version 8.0 you can avoid -XCPP by depending conditionally on `semigroups` via
|
|
|
instance Monoid Foo where
|
|
|
mempty = …
|
|
|
|
|
|
```wiki
|
|
|
if !impl(ghc >= 8.0)
|
|
|
build-depends: semigroups == 0.18.*
|
|
|
#if !(MIN_VERSION_base(5,0,0))
|
|
|
-- assumption: Semigroup becomes superclass w/ base-5.0.0
|
|
|
mappend = (<>)
|
|
|
#endif
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
to provide a legacy `Semigroup` class.
|
|
|
|
|
|
### Alternative w/ conditionally defined `Semigroup` instance & -XCPP
|
|
|
|
|
|
|
|
|
This variant can be used if you require support for GHC \< 8.0 **and** you do **not** want to depend on the `semigroups` package.
|
|
|
|
|
|
```
|
|
|
#ifMIN_VERSION_base(4,9,0)-- Data.Semigroup was added in base-4.9importData.Semigroupas Sem
|
|
|
#endif
|
|
|
#if!(MIN_VERSION_base(4,8,0))-- starting with base-4.8, Monoid is rexported from PreludeimportData.Monoid#endif
|
|
|
|
|
|
appendFoo::Foo->Foo->FooappendFoo=…#ifMIN_VERSION_base(4,9,0)instanceSem.SemigroupFoowhere(<>)= appendFoo
|
|
|
#endif
|
|
|
|
|
|
instanceMonoidFoowhere
|
|
|
mempty =…#ifMIN_VERSION_base(4,11,0)-- starting with base-4.11, mappend definitions are redundant;-- at some point `mappend` will be removed from `Monoid`#elif MIN_VERSION_base(4,9,0)
|
|
|
mappend =(Sem.<>)#else// base <4.9-- prior to GHC 8.0 / base-4.9 where no `Semigroup` class existed
|
|
|
mappend = appendFoo
|
|
|
#endif
|
|
|
|
|
|
```
|
|
|
TODO …integrate migration roadmap outlined in [ http://permalink.gmane.org/gmane.comp.lang.haskell.libraries/24526](http://permalink.gmane.org/gmane.comp.lang.haskell.libraries/24526)
|
|
|
|
|
|
---
|
|
|
|
|
|
TODO …integrate migration roadmap outlined in [ http://permalink.gmane.org/gmane.comp.lang.haskell.libraries/24526](http://permalink.gmane.org/gmane.comp.lang.haskell.libraries/24526) |
|
|
\ No newline at end of file |