5

I have data type:

data Stuff s = Stuff { name :: s, idx :: Int } 

And want to make this into a monoid w/ the following implementations:

tmappend :: Stuff s -> Stuff t -> Stuff (s,t) 
tmappend s1 s2 = Stuff (name s1, name s2) (idx s1 + idx s2)

tzero :: Stuff ()
tzero =  Stuff () 0

Note it's possible to get arbitrarily nested tuples through mconcat.

But tmappend is currently violating the type signature of mappend. Is this actually a monoid? Can it be made into one with a better type representation.

xiaolingxiao
  • 4,793
  • 5
  • 41
  • 88

1 Answers1

16

This is known as a lax monoidal functor. I highly recommend you read this paper which shows how Applicatives are one type of lax monoid and you can reformulate your type as an Applicative and get an equivalent interface:

instance Applicative Stuff where
    pure a = Stuff a 0
    (Stuff f m) <*> (Stuff x n) = Stuff (f x) (m + n)

tmappend :: (Applicative f) => f a -> f b -> f (a, b)
tmappend fa fb = (,) <$> fa <*> fb

tzero :: (Applicative f) => f ()
tzero = pure ()

Notice that tmappend and tzero work for all Applicatives, not just Stuff. The paper I linked discusses this idiom in more detail.

Gabriella Gonzalez
  • 34,863
  • 3
  • 77
  • 135
  • I don't know what a "lax monoid" is, and think you mean "lax monoidal functor." – Philip JF May 29 '13 at 19:50
  • Yes, I meant lax monoidal functor. I'll fix it. – Gabriella Gonzalez May 29 '13 at 19:54
  • 1
    This `Applicative`, incidentally, can be built up from [`Product`](http://hackage.haskell.org/packages/archive/transformers/latest/doc/html/Data-Functor-Product.html), [`Constant`](http://hackage.haskell.org/packages/archive/transformers/latest/doc/html/Data-Functor-Constant.html), [`Identity`](http://hackage.haskell.org/packages/archive/transformers/latest/doc/html/Data-Functor-Identity.html) and [`Sum`](http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-Monoid.html#t:Sum): `type Stuff a = Product (Constant (Sum Int)) Identity a`. – Luis Casillas May 30 '13 at 01:37