W. Zhu
W. Zhu

Reputation: 825

How can I define Pair as a Monoid?

I have my data type Pair defined as

data Pair a b = Pair a b

I would like to make it a monoid. Here is my definition.

instance (Monoid a,Monoid b) => Monoid (Pair a b) where
    mempty = Pair mempty mempty
    mappend (Pair x1 y1) (Pair x2 y2) = Pair (mappend x1 x2) (mappend y1 y2)

However, I got the following error.

foldable.hs:3:10: error:
    • Could not deduce (Semigroup (Pair a b))
        arising from the superclasses of an instance declaration
      from the context: (Monoid a, Monoid b)
        bound by the instance declaration at foldable.hs:3:10-49
    • In the instance declaration for ‘Monoid (Pair a b)’
  |
3 | instance (Monoid a,Monoid b) => Monoid (Pair a b) where
  |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

What went wrong?

Upvotes: 2

Views: 270

Answers (2)

Iceland_jack
Iceland_jack

Reputation: 7014

In the future GHC.Generics will feature a Generically wrapper which allows deriving both instances via Generically (Pair a b)

{-# Language DeriveGeneric #-}
{-# Language DerivingStrategies #-}
{-# Language DerivingVia #-}

import GHC.Generics

-- >> mempty @(Pair String ())
-- Pair "" ()
--
-- >> Pair "hello" () <> Pair " " undefined <> Pair "world" ()
-- Pair "hello world" ()
data Pair a b
  deriving
  stock Generic

  deriving (Semigroup, Monoid)
  via Generically (Pair a b)

This is already possible with generic-data.

Upvotes: 2

amalloy
amalloy

Reputation: 92117

mappend is not really a method of Monoid anymore. You can implement it, but it should be just a synonym for (<>), which is in Semigroup, a superclass of Monoid. To implement Monoid, you must also implement Semigroup, and put your definition of mappend there, named (<>).

Upvotes: 6

Related Questions