首页 文章

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

提问于
浏览
20

GHC有一些语言标志,例如 DeriveFunctorDeriveDataTypeable 等,它们可以为Haskell 98中允许的类型类之外的类型类生成派生实例的编译器 . 这对于像 Functor 这样的东西特别有意义,其中该类的定律规定了很明显,"natural"派生实例 .

为什么不为 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 回答

  • 7

    这是一个任意的决定,不能导出 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 类型的幺半群 . 没有什么比自然方式更突出了 .

  • 15

    你可以问 Num 和其他一些类 . 这将是无关紧要的:所有其他标准派生适用于具有多个构造函数的数据类型 .

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

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

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

相关问题