Почему GHC не может получить экземпляры для Monoid? - программирование
Подтвердить что ты не робот

Почему GHC не может получить экземпляры для Monoid?

GHC имеет несколько языковых флагов, таких как DeriveFunctor, DeriveDataTypeable и т.д., которые позволяют генерировать производные экземпляры для классов классов, отличных от тех, которые разрешены в 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) ...

Я знаю, что derive пакет предоставляет это, но мой вопрос конкретно заключается в том, есть причина, почему GHC не делает.

4b9b3361

Ответ 1

Это действительно произвольное решение не иметь возможности выводить 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. Ничто действительно не выделяется как естественный путь.

Ответ 2

Вы можете задать то же самое для Num и некоторых других классов. Это было бы несущественным: все другие стандартные деривации работают для типов данных с несколькими конструкторами.

В качестве замены вы можете использовать newtype, выводящий newtype T = MkT (a,b,c) deriving Monoid.

Аналогичное расширение: вы можете сделать пустой тип данных экземпляром почти каждого типа.

Предложение deriving всегда было ad-hoc и неудобной частью Haskell, потому что оно работало только для предопределенных классов. Добавление еще более ad-hoc-расширений осложняло бы язык. Вместо этого GHC недавно получил поддержку генерации.