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
。使用第二种方法唯一能避免它们的是一个小样板文件。
假设我想为半群和幺半群定义我自己的类型 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
。使用第二种方法唯一能避免它们的是一个小样板文件。