Home > OS >  Are Maybe String and Maybe Int both Monoids in Haskell?
Are Maybe String and Maybe Int both Monoids in Haskell?

Time:09-05

I´ve gotten into a bit of confusion whether Maybe Int and Maybe String are both monoids in Haskell because i dont really know what functions you can apply to Int or String in terms of monoids with their neutral element and associativity rules! Can anybody help me out?

CodePudding user response:

The Monoid instance for Maybe types has been defined as [src]:

instance Semigroup a => Monoid (Maybe a) where
    mempty = Nothing

it thus requires Int or String to be instances of the Semigroup type class. Since a String is the same as type String = [Char] and thus a list of Chars, this is the case, indeed we see [src]:

instance Semigroup [a] where
        (<>) = (  )
        {-# INLINE (<>) #-}

        stimes = stimesList

so it will append the two lists, and for a Maybe this means [src]:

instance Semigroup a => Semigroup (Maybe a) where
    Nothing <> b       = b
    a       <> Nothing = a
    Just a  <> Just b  = Just (a <> b)

    stimes = stimesMaybe

This thus means that for two Maybe Strings, the neutral element is Nothing and the binary operator will append the two strings wrapped in Just … data constructors if these are both Justs, the Just one if one of the two is a Just, or Nothing if both items are Nothings.

This is not the case for an Int, indeed. For integers there can be multiple Monoid instances, for example ⟨ℤ, , 0⟩ or ⟨ℤ,×, 1⟩.

CodePudding user response:

There is a Monoid instance for any Maybe a as long as a itself has a Monoid instance; the combination of two Just values simply combines the wrapped values according to their instance, while anything combined with Nothing is itself Nothing.

String has a Monoid instance by virtue of being an alias of [Char]; all lists are monoids via list concatenation with the empty list as the identity. As a result, Maybe String is a monoid as well.

> Just "Fo" <> Just "o"
Just "Foo"
> Just "Fo" <> Nothing
Nothing

Maybe Int is not a monoid, because Int is not a monoid. This is because there are multiple choices for how to make Int a monoid, so no one choice is chosen as special. Instead, several new types are defined with distinct Monoid instances to clarify which operation you want to use.

> import Data.Monoid
> (3 :: Int) <> 5

<interactive>:8:1: error:
    • No instance for (Semigroup Int) arising from a use of ‘<>’
    • In the expression: (3 :: Int) <> 5
      In an equation for ‘it’: it = (3 :: Int) <> 5

-- ( ) and 0
> Sum (3 :: Int) <> Sum 5
Sum {getSum = 8}

-- (*) and 1
> Product (3 :: Int) <> Product 5
Product {getProduct = 15}

> Just (Sum (3 :: Int)) <> Just (Sum 5)
Just (Sum {getSum = 8})
> Just (Sum (3 :: Int)) <> Nothing
Nothing
  • Related