Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/Data/Monoid/Extra.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
module Data.Monoid.Extra(
module Data.Monoid,
-- * Extra operations
mwhen
mwhen,

-- * Kleisli endomorphisms
KEndo(KEndo, appKEndo)
) where

import Data.Monoid
import Control.Monad

-- | Like 'Control.Monad.when', but operating on a 'Monoid'. If the first argument
-- is 'True' returns the second, otherwise returns 'mempty'.
Expand All @@ -15,3 +19,16 @@ import Data.Monoid
-- > mwhen False "test" == ""
mwhen :: Monoid a => Bool -> a -> a
mwhen b x = if b then x else mempty

-- | The intersection of 'Data.Monoid.Endo' and 'Control.Arrow.Kleisli'. This
-- type provides a 'Monoid' instance for composition of monadic actions
-- @a -> m a@.
newtype KEndo m a = KEndo { appKEndo :: a -> m a }
Copy link
Copy Markdown
Contributor

@Bodigrim Bodigrim Jul 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be generalized to

newtype Endomorphism k a = Endomorphism (k a a)

instance Category k => Semigroup (Endomorphism k a) where 
  (<>) = coerce (Control.Category..)

instance Category k => Monoid (Endomorphism k a) where 
  mempty = coerce Control.Category.id

Then Endomorphism k a would cover both usual Endo (when k ~ (->)) and monadic endo (when k ~ Kleisli).

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a great idea. That said, once we have gone this far, I wonder if extra is the right place for it? It seems to be more categorical and less compose a few obvious things?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


instance (Monad m) => Semigroup (KEndo m a) where
-- | Right-to-left composition
KEndo f <> KEndo g = KEndo (f <=< g)

instance (Monad m) => Monoid (KEndo m a) where
mempty = KEndo pure