Relationship between class types - dependency versus instance use
Let's say I want to define my own typeclasses for semigroup and monoid. So I write this code:
class Semigroup g where
(<>) :: g -> g -> g
class Semigroup m => Monoid m where
mempty :: m
But in some other way, I could define the relationship between these types of classes with some extensions:
class Semigroup g where
gappend :: g -> g -> g
class Monoid m where
mempty :: m
mappend :: m -> m -> m
instance Monoid m => Semigroup m where
gappend = mappend
The latter design takes precedence. Later I can add more instances for Monoid. For example, if I have a class for a vector space, I can later make it an additive group without specifying it in the class declaration. On the other hand, I am forced to use flexible instances and unsolvable instances.
My question is, what's the best design for this particular case?
source to share
The first version says that "monoids are semigroups with an additional property mempty
".
The second definite says that "all types are semigroups if they are also monoids." If you don't want to include overlapping instances, you cannot add any other instances, so that means "a type is a semigroup if and only if it is a monoid"; exactly back from true relationship.
I would almost always prefer the former. Yes, it makes someone want to add an instance Monoid
to write an instance as well Semigroup
, but the real "work" they have to do is the same either way: decide on the implementation for mempty
and mappend
. The only thing you saved them using the second approach is a small template.
source to share