3

newtype Comparison a is defined in Data.Functor.Contravariant.

In the version of this module defined in contravariant-1.5, the Monoid instance on Contravariant is defined as follows:

instance Monoid (Comparison a) where
  mempty = Comparison (\_ _ -> EQ)
  mappend (Comparison p) (Comparison q) = Comparison $ mappend p q

Data.Functor.Contravariant is also defined in base (as of GHC 8.6.1, apparently). In base, the Monoid instance on Comparison is defined as follows:

deriving instance Semigroup (Comparison a)
deriving instance Monoid (Comparison a)

What enables the instance for Monoid (Comparison a) to be automatically derived in base?

And where should I look to see the definitions of mempty and mappend for it?

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
Joe
  • 1,479
  • 13
  • 22

2 Answers2

6

For newtypes, with GeneralizedNewtypeDeriving enabled, the instance is obtained using the instance of the underlying type.

So, mempty @ a -> a -> Ordering is used (ditto for mappend), and then rewrapped as mappend :: Comparison a.

Note that this ultimately involves the semigroup/monoid instances for function types b -> c and the ones for Ordering.

chi
  • 111,837
  • 3
  • 133
  • 218
5

The Comparison type is just a newtype over a -> a -> Ordering.

Ordering is a Semigroup instance defined in, I think, GHC.Base.

Another relevant instance of Semigroup is:

Semigroup b => Semigroup (a -> b)

That is, any function type a -> b has a Semigroup instance if b has a Semigroup instance.

You can think of a -> a -> Ordering as a -> (a -> Ordering), i.e. a function that takes a as input, and returns (a -> Ordering) as output. Since (a -> Ordering) is a Semigroup instance, then a -> (a -> Ordering) is, too.

The same line of reasoning applies to Monoid.

Finally, as chi wrote in another answer, GeneralizedNewtypeDeriving takes care of the rest.

chepner
  • 497,756
  • 71
  • 530
  • 681
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736