Why can't GHC derive instances for Monoid?
GHC has a few language flags, such as DeriveFunctor
, DeriveDataTypeable
etc., which enable compiler generation of derived instances for type classes other than those allowed in Haskell 98. This especially makes sense for something like Functor
, where the laws of that class dictate an obvious, "natural" derived instance.
So why not for Monoid
? It seems like for any data type with a single data constructor:
data T = MkT a b c ...
one could mechanically produce a Monoid
instance (excuse the pseudocode):
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) ...
I'm aware that the derive package provides this, but my question specifically is whether there's a reason why GHC does not.
It's really an arbitrary decision to not be able to derive Monoid
, but monoids are also very general so there is typically many ways to make a type a monoid. Here's an example:
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
This shows four reasonable ways to make T
a monoid (with Mon
containing the unit and the binary operation). The first is the monoid from taking the maximum, the second the monoid from taking the minimum, the third the monoid from modulo 3 arithmetic, and the fourth is the monoid used for the Ordering
type. Nothing really stands out as the natural way.
You could ask the same for Num
and some other classes. It would be inconsequential: All other standard derivations work for data types with multiple constructors.
As a replacement, you can use newtype deriving newtype T = MkT (a,b,c) deriving Monoid
.
Similar extension: you can make the empty datatype an instance of almost every type class.
The deriving
clause was always ad-hoc and inconvenient part of the Haskell, because it worked only for predefined classes. Adding even more ad-hoc extensions would complicate language. Instead, GHC has recently got support for generic deriving.
上一篇: Haskell中的存在与量化类型
下一篇: 为什么GHC不能为Monoid派生实例?