Search code examples
haskellmonoids

Endofunction as Monoid


I'm trying this (for learning purposes):

{-# LANGUAGE FlexibleInstances #-}

instance Monoid (a -> a) where
  mempty = id
  mappend f g = f . g

expecting id <> id to be equal to id . id

However, with (id <> id) 1 I receive this error:

Non type-variable argument in the constraint: Monoid (a -> a)

What should I change to run it?

It's just to understand monoids and Haskell typeclasses better, not for any practical usage.


Solution

  • This will need {-# OVERLAPPING #-} pragma since GHC.Base has an instance for Monoid (a -> b) when b is a Monoid:

    {-# LANGUAGE FlexibleInstances #-}
    import Data.Monoid (Monoid, mempty, mappend, (<>))
    
    instance {-# OVERLAPPING #-} Monoid (a -> a) where
        mempty = id
        mappend f g = f . g
    

    then, above instance will be invoked for a -> a, even if a is a Monoid:

    \> (id <> id) 1
    1
    \> (id <> id) [1]
    [1]
    

    whereas with Monoid b => a -> b the instance from GHC.Base will be invoked:

    \> ((:[]) <> (:[])) 1
    [1,1]
    

    Note that Data.Monoid provides an exact same instance as yours for a -> a but there the overlap is bypassed using newtype Endo a.