Поскольку вы разрешаете применять любую функцию к списку коэффициентов, ваш тип данных действительно служит только двум целям.
- Вы получаете дополнительную безопасность типов, поскольку
Poly [a]
отличается от [a]
. - Вы можете определить разные экземпляры.
Если вам не нужен ни один из них, вы можете также использовать псевдоним типа.
type Poly a = [a]
Теперь вы можете применить к нему любую функцию списка напрямую.
Если, с другой стороны, вам нужен отдельный тип, вы можете найти пакет newtype
полезным.Например, для данного экземпляра.
instance Newtype (Poly a) [a] where
pack = Poly
unpack (Poly x) = x
Теперь вы можете писать такие вещи, как
foo :: Poly a -> Poly a
foo = over Poly (take 3)
, хотя это может быть излишним, если ваш myMap
достаточен для ваших целей.
Помимо всего этого, я думаю, что представление представления вашего типа данных таким образом, возможно, не было бы хорошей идеей, так как это может оставить остальную часть вашего кода в тесной зависимости от этого представления.
Это затрудняет переход к другому представлению в более позднее время.Например, вы можете захотеть перейти к разреженному представлению, например
data Poly a = Poly [(a, Int)]
, где Int
- это сила термина.Я предлагаю подумать о том, какие операции вы хотите раскрыть, и ограничиться ими.Например, может иметь смысл иметь экземпляр Functor
, который работает для каждого элемента.
instance Functor Poly where
fmap f (Poly x) = Poly $ map f x
Теперь изменение разреженного представления оставляет код клиента неизменным.Только экземпляр (и несколько других функций, которые зависят от представления) должны будут измениться.
instance Functor Poly where
fmap f (Poly x) = Poly $ map (first f) x