1

如何使用从结构中提取标识符(在本例中为整数)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实例(如果上面有多个这样的类型,我们返回从上到下遍历结构时找到的第一个)。现在,当我尝试为产品和总和定义实例时,问题就来了。我想表达类似的东西:IdFuncIdIdGIdentifiable

instance (GIdentifiable a) => GIdentifiable (a :*: b) where
    gGetId (a :*: _) = gGetId a

instance {-# OVERLAPS #-} (GIdentifiable b) => GIdentifiable (a :*: b) where
gGetId (_ :*: b) = gGetId b

这不起作用,因为我正在定义重复的实例。

我可以重新定义IdentifiablegetId :: e -> Maybe Id但这会删除一些类型安全,并在我知道一个类型至少包含一个时引入不必要的检查Id

在使用类型系统时,有没有办法表达这种案例分析?

4

0 回答 0