如何使用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
,但这会删除某些类型的安全性,并在我知道类型包含至少一个{{strong>时 - 引入不必要的检查{1}}。
使用类型系统时,有没有办法表达这种案例分析?