Я хочу создать несколько несовместимых, но в остальном равных типов данных.То есть я хотел бы иметь параметризованный тип Foo a
и такие функции, как
bar :: (Foo a) -> (Foo a) -> (Foo a)
, на самом деле не заботясь о о том, что такое a
.Чтобы уточнить далее, я бы хотел, чтобы система типов не давала мне делать
x :: Foo Int
y :: Foo Char
bar x y
, в то время как меня в то же время не волнуют Int
и Char
(меня интересует только то, что онине то же самое).
В моем реальном коде у меня есть тип для полиномов над данным кольцом.На самом деле меня не волнует, что такое неопределенность, пока система типов мешает мне добавить многочлен от t с многочленом от s.До сих пор я решил эту проблему путем создания класса типов Indeterminate
и параметризации моего полиномиального типа как
data (Ring a, Indeterminate b) => Polynomial a b
Этот подход кажется совершенно естественным для части Ring
, потому что я делаю заботиться о том, какое конкретное кольцо заданный полином закончен.Он выглядит очень надуманным для части Indeterminate
, как подробно описано ниже.
Вышеупомянутый подход работает отлично, но выглядит надуманным.Особенно эта часть:
class Indeterminate a where
indeterminate :: a
data T = T
instance Indeterminate T where
indeterminate = T
data S = S
instance Indeterminate S where
indeterminate = S
(и так далее, возможно, для еще нескольких неопределенностей).Это странно и неправильно.По сути, я пытаюсь потребовать, чтобы экземпляры Indeterminate
были синглетонами (в в этом смысле ).Чувство странности - один из признаков того, что я могу атаковать это неправильно.Другим фактом является то, что мне приходится аннотировать много моих Polynomial a b
с, поскольку фактический тип b
часто не может быть выведен (это не странно, но, тем не менее, раздражает).
Есть предложения?Должен ли я просто продолжать делать это так, или я что-то упустил?
PS: Не обижайтесь, если я не возражаю или не принимаю ответы немедленно.Я не смогу вернуться в течение нескольких дней.