16

"Somewhere" being "in the standard library or in some package that's small and general enough to make it a relatively harmless dependency".

import qualified Data.Map as M
import Data.Monoid
import Control.Applicative

newtype MMap k v = MMap {unMMap :: M.Map k v}
newtype MApplictive f a = MApplicative {unMApplicative :: f a}

-- M.unionWith f M.empty m = M.unionWith f m M.empty = m
-- f a (f b c) = f (f a b) c =>
--    M.unionWith f m1 (M.unionWith f m2 m3) =
--    M.unionWith f (M.unionWith f m1 m2) m3 
instance (Ord k, Monoid v) => Monoid (MMap k v) where
    mempty = MMap $ M.empty
    mappend m1 m2 = MMap $ M.unionWith mappend (unMMap m1) (unMMap m2)


instance (Applicative f, Monoid a) => Monoid (MApplicative f a) where
    mempty = MApplicative $ pure mempty
    mappend f1 f2 = MApplicative $ liftA2 mappend (unMApplicative f1) (unMApplicative f2)

(These instances should satisfy the monoid laws - didn't bother to prove it for the applicative one though)

I'm asking because I have some use for both of those and I don't like to redefine things that are already there.

6
  • 1
    I found this discussion that doesn't say a whole lot about whether such a library exists, but seems to indicate that it doesn't: haskell.org/pipermail/libraries/2012-April/017747.html
    – Emil
    Commented Mar 29, 2014 at 23:19
  • 7
    MApplicative would fulfull the monoid laws pretty much by definition: recall that applicatives are monoidal functors, mathematically! Commented Mar 29, 2014 at 23:34
  • They are strong lax monoidal functors, to be precise!
    – nimish
    Commented Apr 1, 2014 at 15:30
  • 1
    This is when I wish Hoogle or Hayoo! could search the declarations of instances as easily as the declarations of functions.
    – Cirdec
    Commented Apr 2, 2014 at 3:40
  • 1
    I think you could isolate this and put it up on hackage, then depend on it yourself. Commented Dec 1, 2014 at 18:01

3 Answers 3

2

These instances exist in reducers, an Edward Kmett package. Your MApplicative is known there as Ap, while MMap is encoded through the Union newtype. Since base-4.12, Ap has also been available from Data.Monoid.

1

Something like this?

class Functor f => Monoidal f where
    fempty :: Monoid m => f m
    fempty = fconcat []

    fappend :: Monoid m => f m -> f m -> f m
    fappend l r = fconcat [l, r]

    fconcat :: (Foldable c, Monoid m) => c (f m) -> f m
    fconcat = unMWrap $ foldMap MWrap

    {-# MINIMAL fempty, fappend | fconcat #-}

-- Could just be Pointed instead of Applicative, but that's not in base
applicativeFEmpty :: (Applicative f, Monoid m) => f m
applicativeFEmpty = pure mempty

applicativeFAppend :: (Applicative f, Monoid m) => f m -> f m -> f m
applicativeFAppend = liftA2 mappend

applicativeFConcat :: (Applicative f, Monoid m, Foldable c) => c (f m) -> f m
applicativeFConcat = fmap mconcat . sequenceA . foldMap (:[])

newtype MonoidWrap f a = MWrap { unMWrap :: f a }

instance Monoidal f, Monoid m => Monoid (MonoidWrap f m) where
    mempty = MWrap $ fempty . unMWrap
    mappend l r = MWrap $ fappend (unMWap l) (unMWrap r)
    mconcat = MWrap $ fconcat . map unMWrap

Plus, Monoidal instances for all the suitable data types in base? It wouldn't cover Data.Map.Map which is actually my most common use of this pattern, but that could be added simply enough.

Not quite sure about the recursion between mconcat and fconcat. Could be a problem.

1

I think the answer to this question is "No," which is why it has remained without a positive answer for so long.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.