Extracting an Id with GHC.Generics

↘锁芯ラ 提交于 2019-12-06 13:58:12

问题


How to extract an identifier (in this case an integer) from a structure using GHC.Generics?

I have an Id type:

newtype Id = Id { _id :: Int }

and a lot of types that use that type:

data VarId = VarId Name Id SortId
data FuncId = FuncId Name Id [SortId] SortId
data SortId = Name Id
-- ... and 20 more of these things

On top of that there are other types that wrap the types above, for instance, identifiers:

data Identifier = IdVar VarId
                | IdFunc FuncId
                | IdSort SortId
                -- ... and 20 more of these things

Now I need to extract the _id field from any of these types containing an Id value. Currently we have tons of boilerplate for this, and I want to scrap it away using generics.

At first I thought about defining a class:

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

in such a way that you'd have an Identifiable instance only if there is one such Id type inside (in case that there are multiple of those like in FuncId above we return the first Id found when traversing the structure from top to bottom). Now the problem comes when I try to define the GIdentifiable instances for the product and sum. I would like to express something like:

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

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

Which won't work because I'm defining duplicate instances.

I could redefine Identifiable so that getId :: e -> Maybe Id but this will remove some of the type safety, and introduce unnecessary checks when I know that a type contains at least one Id.

Is there a way to express this sort of case analysis when working with the type system?

来源:https://stackoverflow.com/questions/47453657/extracting-an-id-with-ghc-generics

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!