Извлечение идентификатора с помощью 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,

Есть ли способ выразить такой анализ случая при работе с системой типов?

0 ответов

Другие вопросы по тегам