Как организовать модули Haskell с экземплярами: придерживаться типа данных vs type class?
Общий вопрос: какая структура модуля более удобна при добавлении экземпляров для существующих объектов? Какие плюсы и минусы существуют?
Скажем, я хочу добавить экземпляр NFData для типа Seq. Я могу разместить его в:
-
Data.Sequence.Extra
(как то же самое делается в пакете vty)
-
Data.Sequence.Instances.NFData
(точнее)
-
Control.DeepSeq.Instances
-
Control.DeepSeq.Instances.Sequence
Это случай, когда я не владею ни классом типа, ни типом данных. Другая распространенная ситуация - когда я владею классом типа типа и хочу добавлять экземпляры для типов данных из некоторого "тяжелого" пакета из Hackage, например OpenGL. Скажем, класс типа I, который я разработал, очень легкий и не имеет прямого отношения к OpenGL. Я не хочу, чтобы мой тип-класс зависел от "тяжелого" пакета, поэтому я хочу разместить экземпляры OpenGL в отдельном модуле (это мое интуитивное чувство, если у вас есть другое мнение, давайте обсудим его). Итак, каким должен быть этот модуль:
-
MyClass.Instances.OpenGL
-
Graphics.Rendering.OpenGL.Extra
(вместе с экземплярами для других классов)
-
Graphics.Rendering.OpenGL.Instances.MyClass
Что более гибкое решение? В какой-то момент OpenGL можно заменить другой библиотекой, иначе MyClass можно будет заменить. Есть ли тонкие нюансы?
Кроме того, какая схема лучше, если выбрать вариант MyClass.Instances
:
-
MyClass.Class
для самого класса и базовых экземпляров, а модуль MyClass
реэкспортирует его (и, возможно, MyClass.Instances
)
-
MyClass
для класса и базовых экземпляров, а MyClass.All
реэкспортирует все
-
MyClass
модуль для класса и базовых экземпляров и модуль для реэкспорта.
Ответы
Ответ 1
Обычный процесс определения места размещения экземпляра выглядит примерно так:
-
Если вы создаете новый тип данных и хотите иметь экземпляр для существующего класса:
Поместите экземпляр в тот же модуль, что и тип данных.
-
Если вы создаете новый класс типа и хотите создавать экземпляры для существующих типов.
Поместите экземпляры в том же модуле, что и класс типа.
-
И тип типа, и тип данных уже существуют (ваш случай).
Если экземпляр достаточно общий, я должен связаться с автором либо типа или типа данных, либо попытаться убедить их добавить экземпляр в свой пакет.
В противном случае создайте обертку newtype
и напишите для нее экземпляр.
Только в качестве крайней меры рассмотрите возможность создания сиротского экземпляра.