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?

+3


source to share


1 answer


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.

+4


source







All Articles