为什么GHC不能为Monoid派生实例?

时间:2012-06-22 23:15:30

标签: haskell ghc monoids

GHC有一些语言标志,例如DeriveFunctorDeriveDataTypeable等,它们可以为Haskell 98中允许的类型类之外的类型类生成派生实例的编译器。这对某些事情特别有用。比如Functor,那个类的定律决定了一个明显的,“自然的”派生实例。

为什么不Monoid呢?对于具有单个数据构造函数的任何数据类型,似乎都是这样的:

data T = MkT a b c ...

可以机械地产生Monoid实例(原谅伪代码):

instance (Monoid a, Monoid b, Monoid c, ...) => Monoid T where
  mempty =
    MkT mempty mempty mempty ...
  mappend (MkT a1 b1 c1 ...) (MkT a2 b2 c2 ...) =
    MkT (mappend a1 a2) (mappend b1 b2) (mappend c1 c2) ...

我知道deriveprovides this,但我的问题是GHC没有原因。

2 个答案:

答案 0 :(得分:15)

无法导出Monoid这是一个武断的决定,但是幺半群也非常普遍,因此通常有很多方法可以使类型成为一个幺半群。这是一个例子:

data T = A | B | C deriving (Eq, Ord, Enum)

type Mon a = (a, a -> a -> a)

m1, m2, m3, m4 :: Mon T
m1 = (A, max)
m2 = (C, min)
m3 = (A, \ x y -> toEnum $ (fromEnum x + fromEnum y) `rem` 3)
m4 = (B, f4)
f4 A _ = A
f4 B x = x
f4 C _ = C

这显示了使T成为一个monoid的四种合理方法(Mon包含单位和二元运算)。第一个是采用最大值的幺半群,第二个是采用最小值的幺半群,第三个是来自模3算术的幺半群,第四个是用于Ordering类型的幺半群。没有什么比这更自然了。

答案 1 :(得分:7)

您可以对Num和其他一些课程提出同样的要求。这将是无关紧要的:所有其他标准派生适用于具有多个构造函数的数据类型。

作为替代,您可以使用newtype派生newtype T = MkT (a,b,c) deriving Monoid

类似的扩展名:您可以使空数据类型成为几乎所有类型类的实例。

deriving子句始终是临时和不方便的Haskell的一部分,因为它只适用于预定义的类。添加更多临时扩展会使语言复杂化。相反,GHC最近得到了generic deriving的支持。