问题
I have a GADT which is only ever used with two different parameters, ForwardPossible and ():
-- | Used when a forward definition is possible.
data ForwardPossible = ForwardPossible deriving (Eq, Ord, Typeable, Data, Show)
-- | GADT which accepts forward definitions if parameter is ForwardPossible.
data OrForward t forward where
OFKnown :: t -> OrForward t forward
OFForward :: NamespaceID -> SrcSpan -> BS.ByteString -> OrForward t ForwardPossible
deriving instance Eq t => Eq (OrForward t forward)
deriving instance Ord t => Ord (OrForward t forward)
deriving instance Typeable2 OrForward
deriving instance Show t => Show (OrForward t forward)
I would like to derive enough Data.Data instances to cover both OrForward t () and OrForward t ForwardPossible. I don't think a general (Data t, Data forward) => OrForward t forward instance is possible unless it universally ignores OFForward, but either overlapping instances for Data t => OrForward t ForwardPossible and (Data t, Data forward) => OrForward t forward instances could be a solution if there is a way to make ghc derive those instances.
I have tried defining:
deriving instance Data t => Data (OrForward t ())
deriving instance Data t => Data (OrForward t ForwardPossible)
but then ghc gives me an error like this:
Duplicate type signature:
Structure.hs:53:1-70: $tOrForward :: DataType
Structure.hs:52:1-49: $tOrForward :: DataType
回答1:
I found a rather unclean way to work around the problem, so I'll put it here in case no one else finds a better answer:
I created two new modules on top of the main Structure module specifically for deriving instances. I used one to derive instances the GADT specialisation taking ForwardPossible, and one for the instance taking (), making use of StandaloneDeriving and FlexibleInstances. This avoided the issue of conflicting internal symbols from the code added by ghc to implement Data.Data by putting them in different modules.
I had to write instance Data t => Data (OrForward t ()) manually to exclude the OFForward case:
instance Data t => Data (OrForward t ()) where gfoldl k z (OFKnown a1) = (z OFKnown `k` a1) gunfold k z c = case constrIndex c of _ -> k (z OFKnown) toConstr _ = cOFKnown dataTypeOf _ = tOrForward dataCast2 f = gcast2 f tOrForward :: Data.Data.DataType tOrForward = mkDataType "Data.FieldML.Structure.OrForward" [cOFKnown] cOFKnown :: Data.Data.Constr cOFKnown = mkConstr tOrForward "OFKnown" [] Prefix
The instance for Data t => Data (OrForward t ForwardPossible) could be derived:
deriving instance Data t => Data (OrForward t ForwardPossible)
来源:https://stackoverflow.com/questions/12573669/how-can-i-derive-a-data-instance-for-a-gadt-in-haskell