I wanted to implement a Custom Datatype named ComplexNumber like this:
data ComplexNumber a = C (a, a)
Now I want to implement the Monoid variable and define the binary empty element and the mappend like this:
instance Num a => Monoid (ComplexNumber a) where
mempty = C (0,0)
mappend = (C (a1, b1)) (C (a2, b2)) = C (a1 + a2, b1 + b2)
but this didn't work out, so tried to figure out why and came across Semigroup (which I still don't really understand) and came to a solution that at least compiles and seems to work with this:
instance Num a => Semigroup (ComplexNumber a) where
(C (a1, b1)) <> (C (a2,b2)) = C (a1 + a2, b1 + b2)
instance Num a => Monoid (ComplexNumber a) where
mempty = C (0,0)
The funny thing is, when I remove the implementation of Semigroup the program doesn't compile anymore and I get this error:
* Could not deduce (Semigroup (ComplexNumber a))
arising from the superclasses of an instance declaration
from the context: Num a
bound by the instance declaration at Aufgabe_10.hs:9:10-42
* In the instance declaration for `Monoid (ComplexNumber a)'
|
9 | instance Num a => Monoid (ComplexNumber a) where
|
Why is that I can compile those two sections together, but when I remove the semigroup an error occurs ? And what in particular is this Semigroup thing
Semigroup
is just the class of all types that have an implementation of the <>
operation, in a way so that it's associative (i.e. that a<>(b<>c) ≡ (a<>b)<>c
, which does hold true for your complex numbers if we disregard small floating-point deviations).
Monoid
is the class of of semigroups which additionally have a neutral element mempty
, i.e. an element that always fulfills mempty <> a ≡ a <> mempty ≡ a
(also true for complex numbers with addition and zero).
This would be a nonsensical requirement for a type that doesn't even have the <>
operation, i.e. that doesn't have a Semigroup
instance. This is expressed by Semigroup
being a superclass of Monoid
, and thus it's impossible to have a type which is an instance of Monoid
but not of Semigroup
.
Historically, Semigroup
and Monoid
were separate classes, with the older Monoid
shipping its own mappend
operation that is the equivalent to the modern <>
. Some older books / tutorials are still based on this old class hierarchy.
But because there are a bunch of types that are only semigroups, but not monoids, the class hierarchy was changed.