20

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) ...

我知道派生提供了这个,但我的问题特别是 GHC 不提供的原因。

4

2 回答 2

18

不能派生实际上是一个任意的决定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这显示了制作幺半群的四种合理方法(Mon包含单位和二元运算)。第一个是取最大值的幺半群,第二个是取最小值的幺半群,第三个是取模 3 算术的幺半群,第四个是用于Ordering类型的幺半群。没有什么能真正突出自然的方式。

于 2012-06-23T18:00:08.400 回答
8

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

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

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

deriving子句始终是 Haskell 的临时且不方便的部分,因为它仅适用于预定义的类。添加更多的临时扩展会使语言复杂化。相反,GHC 最近获得了对泛型派生的支持。

于 2012-06-23T01:35:57.557 回答