Извлечение идентификатора с помощью GHC.Generics
Как извлечь идентификатор (в данном случае целое число) из структуры, используя GHC.Generics
?
у меня есть Id
тип:
newtype Id = Id { _id :: Int }
и много типов, которые используют этот тип:
data VarId = VarId Name Id SortId
data FuncId = FuncId Name Id [SortId] SortId
data SortId = Name Id
-- ... and 20 more of these things
Кроме того, есть другие типы, которые обертывают типы выше, например, идентификаторы:
data Identifier = IdVar VarId
| IdFunc FuncId
| IdSort SortId
-- ... and 20 more of these things
Теперь мне нужно извлечь _id
поле из любого из этих типов, содержащее Id
значение. В настоящее время у нас есть тонны шаблонного материала для этого, и я хочу избавиться от него, используя дженерики.
Сначала я подумал об определении класса:
class Identifiable e where
getId :: e -> Id
default getId :: (Generic e, GIdentifiable (Rep e)) => e -> Id
getId = gGetId . from
class GIdentifiable f where
gGetId :: f e -> Id
таким образом, что у вас будет Identifiable
экземпляр, только если есть один такой Id
введите внутри (в случае, если есть несколько таких, как в FuncId
выше мы возвращаем первое Id
встречается при обходе конструкции сверху вниз). Теперь проблема возникает, когда я пытаюсь определить GIdentifiable
экземпляры для произведения и суммы. Я хотел бы выразить что-то вроде:
instance (GIdentifiable a) => GIdentifiable (a :*: b) where
gGetId (a :*: _) = gGetId a
instance {-# OVERLAPS #-} (GIdentifiable b) => GIdentifiable (a :*: b) where
gGetId (_ :*: b) = gGetId b
Что не сработает, потому что я определяю дубликаты экземпляров.
Я мог бы переопределить Identifiable
чтобы getId :: e -> Maybe Id
но это удалит некоторые из типов безопасности и введет ненужные проверки, когда я знаю, что тип содержит по крайней мере один Id
,
Есть ли способ выразить такой анализ случая при работе с системой типов?