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

mer*_*ict 20 haskell ghc monoids

GHC有几个语言标志,如DeriveFunctor,DeriveDataTypeable等,使能比那些允许在Haskell 98本其他类型的类派生的实例编译生成特别有意义的东西一样Functor,在这个类的法律规定明显,"自然的"衍生实例".

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

data T = MkT a b c ...
Run Code Online (Sandbox Code Playgroud)

一个人可以机械地产生一个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) ...
Run Code Online (Sandbox Code Playgroud)

我知道派生提供了这个,但我的问题具体是GHC没有的原因.

aug*_*tss 16

这是一个无法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
Run Code Online (Sandbox Code Playgroud)

这显示了制作Tmonoid的四种合理方法(Mon包含单元和二进制操作).第一个是采用最大值的幺半群,第二个是采用最小值的幺半群,第三个是来自模3算术的幺半群,第四个是用于该Ordering类型的幺半群.没有什么比自然方式更突出.


sdc*_*vvc 8

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

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

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

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

  • @mergeconflict对于给定类型,只有一个合理的Functor定义.任何其他有效实例都是等效的.在可折叠和可遍历的情况下,关于如何在字段排序中隐含最佳实践的故事稍微不那么令人满意.所有这些都在多个构造函数上工作,并且没有像Monoid这样的大量替代定义.如果你想要一个monoid元组,只需使用(,,,,). (3认同)
  • 最后它是任意的,但建议的扩展似乎没那么有用.为大多数仿函数提供服务的特殊语言功能对我来说似乎很好.提供产品幺半群的特殊语言功能似乎很难保证添加.你需要考虑范围(如果`Monoid`那么其他什么类?).请注意,有用的monoid通常使用newtype包装器.所以你写`data T = T(Sum Integer)(Endo Char)`来使用这种形式的派生,这有点难以使用(需要在嵌套构造函数上匹配). (2认同)
  • 有很多有用的幺半群是和类型,但是这个实现不能导出它们的任何实例.=( (2认同)