Как я могу получить экземпляр данных для 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 ответ

Я нашел довольно нечистый способ обойти эту проблему, поэтому я приведу его здесь на случай, если никто не найдет лучшего ответа:

  1. Я создал два новых модуля поверх основного модуля Structure специально для создания экземпляров. Я использовал один для получения экземпляров специализации GADT, принимающий ForwardPossible, и один для экземпляра take (), использующий StandaloneDeriving и FlexibleInstances. Это позволило избежать конфликта внутренних символов из кода, добавленного ghc для реализации Data.Data, путем помещения их в разные модули.

  2. Мне пришлось написать экземпляр 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
    
  3. Экземпляр для Data t => Data (OrForward t ForwardPossible) может быть получен:

    deriving instance Data t => Data (OrForward t ForwardPossible)
    
Другие вопросы по тегам