Как я могу получить экземпляр данных для GADT в Haskell?
У меня есть GADT, который когда-либо используется только с двумя разными параметрами, ForwardPossible и ():
-- | 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)
Я хотел бы получить достаточно экземпляров Data.Data, чтобы покрыть как OrForward t (), так и OrForward t ForwardPossible. Я не думаю, что общий (Data t, Data forward) => OrForward t экземпляр пересылки возможен, если только он не игнорирует универсально OFForward, а либо перекрывающиеся экземпляры для Data t => OrForward t ForwardPossible и (Data t, Data forward) => Или Forward t forward экземпляры могут быть решением, если есть способ заставить ghc получить эти экземпляры.
Я попытался определить:
deriving instance Data t => Data (OrForward t ())
deriving instance Data t => Data (OrForward t ForwardPossible)
но тогда GHC дает мне ошибку, как это:
Duplicate type signature:
Structure.hs:53:1-70: $tOrForward :: DataType
Structure.hs:52:1-49: $tOrForward :: DataType
1 ответ
Я нашел довольно нечистый способ обойти эту проблему, поэтому я приведу его здесь на случай, если никто не найдет лучшего ответа:
Я создал два новых модуля поверх основного модуля Structure специально для создания экземпляров. Я использовал один для получения экземпляров специализации GADT, принимающий ForwardPossible, и один для экземпляра take (), использующий StandaloneDeriving и FlexibleInstances. Это позволило избежать конфликта внутренних символов из кода, добавленного ghc для реализации Data.Data, путем помещения их в разные модули.
Мне пришлось написать экземпляр Data t => Data (OrForward t ()) вручную, чтобы исключить случай OFForward:
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
Экземпляр для Data t => Data (OrForward t ForwardPossible) может быть получен:
deriving instance Data t => Data (OrForward t ForwardPossible)