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

person a1kmm    schedule 24.09.2012    source источник
comment
Небольшое примечание: если вы используете GHC 7.4 или 7.6 с DataKinds, у вас может быть data OrForward t (forward :: Bool), а затем ваши два типа - OrForward t True и OrForward t False (или, конечно, вы можете создать свой собственный 2 типа и использовать его вместо Bool).   -  person Cactus    schedule 25.09.2012


Ответы (1)


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

  1. Я создал два новых модуля поверх основного модуля структуры специально для создания экземпляров. Я использовал один для получения экземпляров, в которых специализация 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)
    
person a1kmm    schedule 24.09.2012