Основной вопрос: каким принципам проектирования следует придерживаться при выборе между использованием класса или использованием записи (с полиморфными полями)?
Во-первых, мы знаем, что классы и записи по сути эквивалентны (поскольку в Core классы обесцениваются до словарей, которые являются просто записями). Тем не менее, есть отличия: классы передаются неявно, записи должны быть явными.
Если заглянуть немного глубже, классы действительно полезны, когда:
Классы неудобны, когда у нас есть (вплоть до параметрического полиморфизма) только одно представление наших данных, но у нас есть несколько экземпляров.Это приводит к синтаксическому шуму из-за необходимости использовать newtype для добавления дополнительных тегов (которые существуют только в нашем коде, поскольку мы знаем, что такие теги стираются во время выполнения), если мы не хотим включать все разновидности проблемных расширений (например, перекрывающиеся и / или неразрешимые экземпляры).
Конечно, все становится еще запутаннее: что, если я хочу иметь ограничения на свои типы? Давайте возьмем реальный пример:
class (Bounded i, Enum i) => Partition a i where
index :: a -> i
Я мог бы так же легко сделать
data Partition a i = Partition { index :: a -> i}
Но теперь я потерял свои ограничения, и вместо этого мне придется добавить их к определенным функциям.
Есть ли рекомендации по дизайну, которые могут мне помочь?