У меня есть тип данных, который является экземпляром Monoid
, поэтому я могу получить красивую композицию значений:
data R a = R String (Maybe (String → a))
instance Monoid (R a) where
mempty = R "" Nothing
R s f `mappend` R t g = R (s ++ t) (case g of Just _ → g; Nothing → f)
Далее, я не хочу комбинировать все значения R a
друг с другом, это не имеет смысла в моем домене. Поэтому я представляю phantom тип t
:
{-# LANGUAGE DataKinds, KindSignatures #-}
data K = T1 | T2
data R (t ∷ K) a = R String (Maybe (String → a))
instance Monoid (R t a) where …
Итак, у меня есть "ограниченные" значения:
v1 ∷ R T1 Int
v2 ∷ R T2 Int
-- v1 <> v2 => type error
и "неограниченный":
v ∷ R t Int
-- v <> v1 => ok
-- v <> v2 => ok
Но теперь у меня проблема. Когда дело доходит до v30
, например:
- У меня было бы огромное объявление типа
datastrike > (data K = T1 | … | T30
). Я мог бы решить, используя naturals типа уровня, чтобы получить бесконечный источник типов phantom (лечение хуже, чем болезнь, не так ли?). - Я должен помнить, какой тип phantom для какого значения использовать при написании сигнатур типов в зависимом коде (это действительно раздражает)
Существует ли более простой подход к ограничению состава?