packages feed

monoid-extras 0.6.5 → 0.7

raw patch · 5 files changed

+147/−185 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Data.Monoid.Coproduct: instance (GHC.Classes.Eq m, GHC.Classes.Eq n, GHC.Base.Semigroup m, GHC.Base.Semigroup n) => GHC.Classes.Eq (m Data.Monoid.Coproduct.:+: n)
- Data.Monoid.Coproduct.Strict: _L :: (Action m n, Monoid m, Semigroup n) => Lens (m :+: n) (m' :+: n) m m'
- Data.Monoid.Coproduct.Strict: _R :: (Action m n, Monoid' n) => Lens (m :+: n) (m :+: n') n n'
- Data.Monoid.Coproduct.Strict: data m :+: n
- Data.Monoid.Coproduct.Strict: inL :: m -> m :+: n
- Data.Monoid.Coproduct.Strict: inR :: n -> m :+: n
- Data.Monoid.Coproduct.Strict: instance (Data.Monoid.Action.Action m n, Data.Monoid.Action.Action m r, Data.Monoid.Action.Action n r, GHC.Base.Semigroup n) => Data.Monoid.Action.Action (m Data.Monoid.Coproduct.Strict.:+: n) r
- Data.Monoid.Coproduct.Strict: instance (Data.Monoid.Action.Action m n, GHC.Base.Monoid m, Data.Monoid.WithSemigroup.Monoid' n, GHC.Show.Show m, GHC.Show.Show n) => GHC.Show.Show (m Data.Monoid.Coproduct.Strict.:+: n)
- Data.Monoid.Coproduct.Strict: instance (Data.Monoid.Action.Action m n, GHC.Base.Semigroup m, GHC.Base.Semigroup n) => GHC.Base.Monoid (m Data.Monoid.Coproduct.Strict.:+: n)
- Data.Monoid.Coproduct.Strict: instance (Data.Monoid.Action.Action m n, GHC.Base.Semigroup m, GHC.Base.Semigroup n) => GHC.Base.Semigroup (m Data.Monoid.Coproduct.Strict.:+: n)
- Data.Monoid.Coproduct.Strict: instance GHC.Base.Semigroup a => GHC.Base.Monoid (Data.Monoid.Coproduct.Strict.Possible a)
- Data.Monoid.Coproduct.Strict: instance GHC.Base.Semigroup a => GHC.Base.Semigroup (Data.Monoid.Coproduct.Strict.Possible a)
- Data.Monoid.Coproduct.Strict: killL :: (Action m n, Monoid' n) => (m :+: n) -> n
- Data.Monoid.Coproduct.Strict: killR :: Monoid m => (m :+: n) -> m
- Data.Monoid.Coproduct.Strict: prependL :: Semigroup m => m -> (m :+: n) -> m :+: n
- Data.Monoid.Coproduct.Strict: prependR :: Semigroup n => n -> (m :+: n) -> m :+: n
- Data.Monoid.Coproduct.Strict: untangle :: (Action m n, Monoid m, Monoid' n) => (m :+: n) -> (m, n)
- Data.Monoid.Coproduct.Strict: untangled :: (Action m n, Monoid m, Monoid' n) => Lens (m :+: n) (m' :+: n') (m, n) (m', n')
+ Data.Monoid.Coproduct: cop :: Monoid k => (m -> k) -> (n -> k) -> (m :+: n) -> k
+ Data.Monoid.Coproduct: instance (GHC.Classes.Eq m, GHC.Classes.Eq n, GHC.Base.Monoid m, GHC.Base.Monoid n) => GHC.Classes.Eq (m Data.Monoid.Coproduct.:+: n)
+ Data.Monoid.Coproduct: toReducedAltList :: (Eq m, Eq n, Monoid m, Monoid n) => (m :+: n) -> [Either m n]
+ Data.Monoid.Coproduct: untangleSemi :: (Action m n, Monoid m, Monoid n) => (m :+: n) -> Semi n m
+ Data.Semigroup.Coproduct: cop :: Semigroup k => (m -> k) -> (n -> k) -> (m :+. n) -> k
+ Data.Semigroup.Coproduct: data m :+. n
+ Data.Semigroup.Coproduct: inL :: m -> m :+. n
+ Data.Semigroup.Coproduct: inR :: n -> m :+. n
+ Data.Semigroup.Coproduct: instance (Data.Monoid.Action.Action m r, Data.Monoid.Action.Action n r) => Data.Monoid.Action.Action (m Data.Semigroup.Coproduct.:+. n) r
+ Data.Semigroup.Coproduct: instance (GHC.Classes.Eq m, GHC.Classes.Eq n, GHC.Base.Semigroup m, GHC.Base.Semigroup n) => GHC.Classes.Eq (m Data.Semigroup.Coproduct.:+. n)
+ Data.Semigroup.Coproduct: instance (GHC.Show.Show m, GHC.Show.Show n) => GHC.Show.Show (m Data.Semigroup.Coproduct.:+. n)
+ Data.Semigroup.Coproduct: instance GHC.Base.Semigroup (m Data.Semigroup.Coproduct.:+. n)
+ Data.Semigroup.Coproduct: toAltList :: (Semigroup m, Semigroup n) => (m :+. n) -> NonEmpty (Either m n)
+ Data.Semigroup.Coproduct: toMonoid :: (Monoid m, Monoid n) => (m :+. n) -> m :+: n
- Data.Monoid.Endomorphism: Endomorphism :: k a a -> Endomorphism k a
+ Data.Monoid.Endomorphism: Endomorphism :: k a a -> Endomorphism (k :: Type -> Type -> Type) a
- Data.Monoid.Endomorphism: [getEndomorphism] :: Endomorphism k a -> k a a
+ Data.Monoid.Endomorphism: [getEndomorphism] :: Endomorphism (k :: Type -> Type -> Type) a -> k a a
- Data.Monoid.Endomorphism: newtype Endomorphism k a
+ Data.Monoid.Endomorphism: newtype Endomorphism (k :: Type -> Type -> Type) a

Files

CHANGES view
@@ -1,3 +1,15 @@+* 0.7: 12 May 2025++  - Updates to `Data.Monoid.Coproduct`:+    - Fix `Eq` instance for monoid coproducts to take `mempty` into account+    - `cop` implements coproduct universal map+    - `untangleSemi`, like `untangle` but as a monoid homomorphism to semidirect product+    - `toReducedAltList`, like `toAltList` but also gets rid of `mempty`+  - New module `Data.Semigroup.Coproduct` with semigroup coproducts+  - Remove `Data.Monoid.Coproduct.Strict`++  Thanks to Sonat Süer (@sonatsuer) for the updates!+ * 0.6.5: 22 February 2025  - New instance `Eq (m :+: n)` ([#59](https://github.com/diagrams/monoid-extras/issues/59))
monoid-extras.cabal view
@@ -1,5 +1,5 @@ name:                monoid-extras-version:             0.6.5+version:             0.7 synopsis:            Various extra monoid-related definitions and utilities description:         Various extra monoid-related definitions and utilities,                      such as monoid actions, monoid coproducts, semi-direct@@ -26,7 +26,6 @@                      Data.Monoid.SemiDirectProduct,                      Data.Monoid.SemiDirectProduct.Strict                      Data.Monoid.Coproduct,-                     Data.Monoid.Coproduct.Strict,                      Data.Monoid.Cut,                      Data.Monoid.Deletable,                      Data.Monoid.Endomorphism,@@ -34,7 +33,8 @@                      Data.Monoid.MList,                      Data.Monoid.Recommend,                      Data.Monoid.Split,-                     Data.Monoid.WithSemigroup+                     Data.Monoid.WithSemigroup,+                     Data.Semigroup.Coproduct    build-depends:     base >= 4.11 && < 4.22,                      groups < 0.6,
src/Data/Monoid/Coproduct.hs view
@@ -19,29 +19,32 @@        ( (:+:)        , inL, inR        , mappendL, mappendR+       , cop        , killL, killR        , toAltList+       , toReducedAltList        , untangle-+       , untangleSemi        ) where -import Data.Either        (lefts, rights) import Data.Function      (on) import Data.Semigroup import Data.Typeable  import Data.Monoid.Action+import Data.Monoid.SemiDirectProduct ( embed, inject, Semi, unSemi )+import Data.Tuple (swap)  -- | @m :+: n@ is the coproduct of monoids @m@ and @n@.  Values of --   type @m :+: n@ consist of alternating lists of @m@ and @n@---   values.  The empty list is the identity, and composition is list+--   values. The empty list is the identity, and composition is list --   concatenation, with appropriate combining of adjacent elements---   when possible.+--   and removing identities when possible. newtype m :+: n = MCo { unMCo :: [Either m n] }   deriving (Typeable, Show) -instance (Eq m, Eq n, Semigroup m, Semigroup n) => Eq (m :+: n) where-  (==) = (==) `on` (normalize . unMCo)+instance (Eq m, Eq n, Monoid m, Monoid n) => Eq (m :+: n) where+  (==) = (==) `on` (normalizeEq . unMCo)  -- | Extract a monoid coproduct to a list of @Either@ values.  The --   resulting list is guaranteed to be normalized, in the sense that@@ -49,6 +52,13 @@ toAltList :: (Semigroup m, Semigroup n) => (m :+: n) -> [Either m n] toAltList (MCo ms) = normalize ms +-- | Extract a monoid coproduct to a list of @Either@ values.  The+--   resulting list is guaranteed to be normalized, in the sense that+--   it will strictly alternate between @Left@ and @Right@ and no identity+--   element from @m@ or @n@ will occur in the list.+toReducedAltList :: (Eq m, Eq n, Monoid m, Monoid n) => (m :+: n) -> [Either m n]+toReducedAltList (MCo ms) = normalizeEq ms+ -- Normalize a list of @Either@ values by combining any consecutive -- values of the same type. normalize :: (Semigroup m, Semigroup n) => [Either m n] -> [Either m n]@@ -58,11 +68,30 @@   []  -> []   (e:es) -> e : normalize es ++-- Similar to @normalize@. In addition to combining consecutive values of the same+-- type it also removes the identities.+normalizeEq :: (Eq m, Eq n, Monoid m, Monoid n) => [Either m n] -> [Either m n]+normalizeEq es = until (all nonIdentity) reduce (normalize es)+  where+    reduce = normalize . filter nonIdentity+    nonIdentity e = e /= Left mempty && e /= Right mempty+ -- For efficiency and simplicity, we implement it just as [Either m -- n]: of course, this does not preserve the invariant of strictly -- alternating types, but it doesn't really matter as long as we don't -- let anyone inspect the internal representation. +-- | Universal map of the coproduct. The name @cop@ is an abbreviation+--   for copairing. Both functions in the signature should be monoid+--   homomorphisms. If they are general functions then the copairing may+--   not be well defined in the sense that it may send equal elements to+--   unequal elements. This is also the reason why @cop@ is not the+--   @Data.Bifoldable.bifoldMap@ function even though they have the same+--   signature.+cop :: Monoid k => (m -> k) -> (n -> k) -> (m :+: n) -> k+f `cop` g = foldMap (either f g) . unMCo+ -- | Injection from the left monoid into a coproduct. inL :: m -> m :+: n inL m = MCo [Left m]@@ -90,14 +119,21 @@ -- | @killR@ takes a value in a coproduct monoid and sends all the --   values from the right monoid to the identity. killR :: Monoid m => m :+: n -> m-killR = mconcat . lefts . unMCo+killR = id `cop` const mempty  -- | @killL@ takes a value in a coproduct monoid and sends all the --   values from the left monoid to the identity. killL :: Monoid n => m :+: n -> n-killL = mconcat . rights . unMCo+killL = const mempty `cop` id --- | Take a value from a coproduct monoid where the left monoid has an+-- | The copairing of @embed@ and @inject@ homomorphisms into the+--   semidirect product. Note that @embed@ and @inject@ are monoid+--   homomorphisms. Therefore @untangleSemi@ is also a monoid homomorphism.+untangleSemi :: (Action m n, Monoid m, Monoid n) => m :+: n -> Semi n m+untangleSemi = embed `cop` inject++-- | Same as @untangleSemi@ but the result is uwrapped. Concretely, given+--   a value from a coproduct monoid where the left monoid has an --   action on the right, and \"untangle\" it into a pair of values.  In --   particular, --@@ -110,12 +146,9 @@ --   That is, before combining @n@ values, every @n@ value is acted on --   by all the @m@ values to its left. untangle :: (Action m n, Monoid m, Monoid n) => m :+: n -> (m,n)-untangle (MCo elts) = untangle' mempty elts-  where untangle' cur [] = cur-        untangle' (curM, curN) (Left m : elts')  = untangle' (curM `mappend` m, curN) elts'-        untangle' (curM, curN) (Right n : elts') = untangle' (curM, curN `mappend` act curM n) elts'+untangle = swap . unSemi . untangleSemi  -- | Coproducts act on other things by having each of the components --   act individually. instance (Action m r, Action n r) => Action (m :+: n) r where-  act = appEndo . mconcat . map (Endo . either act act) . unMCo+  act = appEndo . ((Endo . act) `cop` (Endo . act))
− src/Data/Monoid/Coproduct/Strict.hs
@@ -1,168 +0,0 @@-{-# LANGUAGE BangPatterns          #-}-{-# LANGUAGE ConstraintKinds       #-}-{-# LANGUAGE FlexibleInstances     #-}-{-# LANGUAGE MonoLocalBinds        #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes            #-}-{-# LANGUAGE TypeOperators         #-}---------------------------------------------------------------------------------- |--- Module      :  Data.Monoid.Coproduct.Strict--- Copyright   :  (c) 2015 diagrams-core team (see LICENSE)--- License     :  BSD-style (see LICENSE)--- Maintainer  :  diagrams-discuss@googlegroups.com------ A strict coproduct of two monoids.-----------------------------------------------------------------------------------module Data.Monoid.Coproduct.Strict-  (-    -- * Coproduct-    (:+:)-  , inL, inR-  , prependL, prependR-  , killL, killR-  , untangle--  -- ** Lenses-  , untangled-  , _L-  , _R--  ) where--import           Data.Monoid.Action-import           Data.Monoid.WithSemigroup-import           Data.Semigroup-import           Prelude---- Internal strict version of Maybe-data Possible a = Only !a | Nought--instance Semigroup a => Semigroup (Possible a) where-  Only a <> Only b = Only (a <> b)-  Nought <> b      = b-  a      <> _      = a-  {-# INLINE (<>) #-}--instance Semigroup a => Monoid (Possible a) where-  mempty = Nought-  {-# INLINE mempty #-}-  mappend = (<>)-  {-# INLINE mappend #-}---- | @m :+: n@ is the coproduct of monoids @m@ and @n@. Concatentation---   is equivilent to------ @--- (m1 :+: n1) <> (m2 :+: n2) = (m1 <> m2) :+: (n1 <> act m1 n2)@--- @------   but has a more efficient internal implimentation.-data m :+: n = C !(Possible n) !(Possible m) !(Possible n)--- The left n already has the action m applied. The right n still needs--- m applied, but it kept there incase more n comes to reduce the number--- of actions that need to be applied.--instance (Action m n, Monoid m, Monoid' n, Show m, Show n) => Show (m :+: n) where-  showsPrec p c = showParen (p > 5) $-    showsPrec 11 m . showString " :+: " . showsPrec 11 n-    where (m,n) = untangle c--instance (Action m n, Semigroup m, Semigroup n) => Semigroup (m :+: n) where-  C n1 m1 o1 <> C n2 m2 o2 = C (n1 <> act' m1 (o1 <> n2)) (m1 <> m2) o2-  {-# INLINE (<>) #-}--instance (Action m n, Semigroup m, Semigroup n) => Monoid (m :+: n) where-  mempty  = C Nought Nought Nought-  {-# INLINE mempty #-}-  mappend = (<>)-  {-# INLINE mappend #-}---- | Coproducts act on other things by having each of the components---   act individually.-instance (Action m n, Action m r, Action n r, Semigroup n) => Action (m :+: n) r where-  act (C n m o) = act'' n' . act'' m-    where !n' = n <> act' m o-  {-# INLINE act #-}---- | Construct a coproduct with a left value.-inL :: m -> m :+: n-inL m = C Nought (Only m) Nought-{-# INLINE inL #-}---- | Construct a coproduct with a right value.-inR :: n -> m :+: n-inR r = C (Only r) Nought Nought-{-# INLINE inR #-}---- | Prepend a value from the left.-prependL :: Semigroup m => m -> m :+: n -> m :+: n-prependL m' (C n m o) = C n (Only m' <> m) o-{-# INLINE prependL #-}---- | Prepend a value from the right.-prependR :: Semigroup n => n -> m :+: n -> m :+: n-prependR n' (C n m o) = C (Only n' <> n) m o-{-# INLINE prependR #-}---- | Extract @m@ from a coproduct.-killR :: Monoid m => m :+: n -> m-killR (C _ m _) = get m-{-# INLINE killR #-}---- | Extract @n@ from a coproduct.-killL :: (Action m n, Monoid' n) => m :+: n -> n-killL (C n m o) = get $ n <> act' m o-{-# INLINE killL #-}--untangle :: (Action m n, Monoid m, Monoid' n) => m :+: n -> (m,n)-untangle (C n m o) = (get m, get n')-  where !n' = n <> act' m o-{-# INLINE untangle #-}---- Lenses ----------------------------------------------------------------type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t---- | Lens onto the both @m@ and @n@.-untangled :: (Action m n, Monoid m, Monoid' n) => Lens (m :+: n) (m' :+: n') (m,n) (m',n')-untangled f c = f (untangle c) <&> \(m',n') -> C (Only n') (Only m') Nought-{-# INLINE untangled #-}--- this could be an iso if we depended on profunctors---- | Lens onto the left value of a coproduct.-_L :: (Action m n, Monoid m, Semigroup n) => Lens (m :+: n) (m' :+: n) m m'-_L f (C n m o) = f (get m) <&> \m' -> C (n <> act' m o) (Only m') Nought-{-# INLINE _L #-}--- this could be a prism if we depended on profunctors---- | Lens onto the right value of a coproduct.-_R :: (Action m n, Monoid' n) => Lens (m :+: n) (m :+: n') n n'-_R f (C n m o) = f (get $ n `mappend` act' m o) <&> \n' -> C (Only n') m Nought-{-# INLINE _R #-}---- Internal utilities ----------------------------------------------------get :: Monoid a => Possible a -> a-get (Only a) = a-get _        = mempty-{-# INLINE get #-}--(<&>) :: Functor f => f a -> (a -> b) -> f b-(<&>) = flip fmap-{-# INLINE (<&>) #-}---- Act on a possible with a possible-act' :: Action m n => Possible m -> Possible n -> Possible n-act' (Only m) (Only n) = Only (act m n)-act' _        n        = n-{-# INLINE act' #-}---- Act with a possible-act'' :: Action m n => Possible m -> n -> n-act'' (Only m) = act m-act'' _        = id-{-# INLINE act'' #-}
+ src/Data/Semigroup/Coproduct.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE DeriveDataTypeable    #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE LambdaCase #-}++module Data.Semigroup.Coproduct+       ( (:+.)+       , inL, inR+       , cop+       , toAltList+       , toMonoid+       ) where++import Data.Function (on)+import Data.List.NonEmpty (NonEmpty(..))+import Data.Typeable (Typeable)+import Data.Semigroup (Endo(Endo, appEndo))+import Data.Semigroup.Foldable (foldMap1)++import Data.Monoid.Action (Action(..))+import Data.Monoid.Coproduct ((:+:))+import qualified Data.Monoid.Coproduct as M++-- | @m :+. n@ is the coproduct of semigroups @m@ and @n@.  Values of+--   type @m :+. n@ consist of alternating non-empty lists of @m@ and @n@+--   values. Composition is list concatenation, with appropriate+--   combining of adjacent elements+newtype m :+. n = SCo { unSCo :: NonEmpty (Either m n) }+  deriving (Typeable, Show)++instance (Eq m, Eq n, Semigroup m, Semigroup n) => Eq (m :+. n) where+  (==) = (==) `on` (normalize . unSCo)++-- | Extract a semigroup coproduct to a non-empty list of @Either@ values.+--   The resulting list is guaranteed to be normalized, in the sense that+--   it will strictly alternate between @Left@ and @Right@.+toAltList :: (Semigroup m, Semigroup n) => (m :+. n) -> NonEmpty (Either m n)+toAltList (SCo ms) = normalize ms++-- Normalize a list of @Either@ values by combining any consecutive+-- values of the same type.+normalize :: (Semigroup m, Semigroup n) => NonEmpty (Either m n) -> NonEmpty (Either m n)+normalize = \case+  Left e1 :| Left e2 : es -> normalize (Left (e1 <> e2) :| es)+  Right e1 :| Right e2 : es -> normalize (Right (e1 <> e2) :| es)+  e1 :| es1 -> case es1 of+    e2 : es2 -> (e1 :| []) <> normalize (e2 :| es2)+    [] -> e1 :| []++-- | Universal map of the coproduct. The name @cop@ is an abbreviation+--   for copairing. Both functions in the signature should be semigroup+--   homomorphisms. If they are general functions then the copairing may+--   not be well defined in the sense that it may send equal elements to+--   unequal elements. This is also the reason why @cop@ is not the+--   @Data.Bifoldable1.bifoldMap1@ function even though they have the same+--   signature.+cop :: Semigroup k => (m -> k) -> (n -> k) -> (m :+. n) -> k+f `cop` g = foldMap1 (either f g) . unSCo++-- | Injection from the left semigroup into a coproduct.+inL :: m -> m :+. n+inL m = SCo (Left m :| [])++-- | Injection from the right semigroup into a coproduct.+inR :: n -> m :+. n+inR n = SCo (Right n :| [])++-- | Given monoids @m@ and @n@, we can form their semigroup coproduct+--   @m :+. n@. Every monoid homomorphism is a semigroup homomorphism.+--   In particular the canonical inections of the monoid coproduct from+--   @m@ and @n@ into @m :+: n@ are semigroup homomorphisms. By pairing+--   them using the universal property of the semigroup coproduct we+--   obtain a canonical semigroup homomorphism `toMonoid` from @m :+. n@+--   to @m :+: n@.+toMonoid :: (Monoid m, Monoid n) => m :+. n -> m :+: n+toMonoid = M.inL `cop` M.inR++instance Semigroup (m :+. n) where+  (SCo es1) <> (SCo es2) = SCo (es1 <> es2)++-- | Coproducts act on other things by having each of the components+--   act individually.+instance (Action m r, Action n r) => Action (m :+. n) r where+  act = appEndo . ((Endo . act) `cop` (Endo . act))