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 Char
s, 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 String
s, the neutral element is Nothing
and the binary operator will append the two strings wrapped in Just …
data constructors if these are both Just
s, the Just
one if one of the two is a Just
, or Nothing
if both items are Nothing
s.
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