type 类 - dependency vs using instance 之间的关系

The relationship between type classes - dependency vs using instance

假设我想为半群和幺半群定义我自己的类型 classes。所以我写了这段代码:

class Semigroup g where
    (<>) :: g -> g -> g

class Semigroup m => Monoid m where
    mempty :: m

但是我可以通过另一种方式定义这些类型 class 之间的关系,并进行一些扩展:

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

后一种设计有一个优势——以后我可以为Monoid添加更多的实例。例如,如果我有一个向量 space 的类型 class,我可以稍后将其设为加法组,而不必在 class 声明中指定它。另一方面,我被迫使用灵活的实例和不可判定的实例。

我的问题是 - 这个特定案例的最佳设计是什么?

第一个版本说 "monoids are semigroups, with the additional property mempty"。

第二个说"all types are semigroups, provided they are also monoids"。除非您乐于打开重叠实例,否则您无法添加任何其他实例,因此这相当于 "a type is a semigroup if and only if it is a monoid";与真实关系完全相反。

我几乎总是喜欢前者。是的,它迫使想要添加 Monoid 实例的人也编写一个 Semigroup 实例,但真正的 "work" 他们必须做的是相同的两种方式:决定 [= 的实现10=] 和 mappend。使用第二种方法唯一能避免它们的是一个小样板文件。