【问题标题】:How can I derive a Data instance for a GADT in Haskell?如何在 Haskell 中为 GADT 派生数据实例?
【发布时间】:2012-09-16 10:08:40
【问题描述】:

我有一个 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 forward 实例是不可能的,除非它普遍忽略 OFForward,但是 Data t => OrForward t ForwardPossible 和 (Data t, Data forward) => 的重叠实例如果有办法让 ghc 派生这些实例,OrForward t 前向实例可能是一个解决方案。

我尝试过定义:

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

【问题讨论】:

  • 作为一个小提示,如果您使用 GHC 7.4 或 7.6 和 DataKinds,您可以使用 data OrForward t (forward :: Bool),然后您的两种类型是 OrForward t TrueOrForward t False(或者当然您可以制作自己的 2 种类型并使用它来代替 Bool)。

标签: haskell gadt deriving


【解决方案1】:

我找到了一个相当不干净的方法来解决这个问题,所以我会把它放在这里以防其他人找到更好的答案:

  1. 我在主结构模块之上创建了两个新模块,专门用于派生实例。我用一个来派生实例,使用 ForwardPossible 的 GADT 专业化,一个用于实例的 (),利用 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)
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多