【问题标题】:Can I derive a newtype instance of `Data`?我可以派生一个新类型的“数据”实例吗?
【发布时间】:2018-09-25 10:55:21
【问题描述】:

我有一个新类型T

newtype T = T Text

我想为它派生Data。所以-XGeneralizedNewtypeDeriving -XDerivingStrategies 我愿意

deriving newtype instance Data T

我希望这对于 GHC 来说是一个不费吹灰之力的推导,但我收到了一条令人讨厌的错误消息(附在下面)。该错误消息似乎来自coerce 的应用程序,由newtype 派生引起。

如果我正确理解角色注释,他们将需要在Data 的实例方法上进行类型声明,但没有。我需要滚动我自己的实例吗?

    • Couldn't match representation of type ‘c1 Text’
                               with that of ‘c1 T’
        arising from a use of ‘ghc-prim-0.5.2.0:GHC.Prim.coerce’
      NB: We cannot know what roles the parameters to ‘c1’ have;
        we must assume that the role is nominal
    • In the expression:
        ghc-prim-0.5.2.0:GHC.Prim.coerce
          @(forall (c :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep
                         -> TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep).
            forall (d :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep)
                   (b :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep).
            Data d => c (d -> b) -> d -> c b
            -> forall (g :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep).
               g -> c g
               -> Text -> c Text)
          @(forall (c :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep
                         -> TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep).
            forall (d :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep)
                   (b :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep).
            Data d => c (d -> b) -> d -> c b
            -> forall (g :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep).
               g -> c g
               -> T -> c T)
          gfoldl
      In an equation for ‘gfoldl’:
          gfoldl
            = ghc-prim-0.5.2.0:GHC.Prim.coerce
                @(forall (c :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep
                               -> TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep).
                  forall (d :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep)
                         (b :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep).
                  Data d => c (d -> b) -> d -> c b
                  -> forall (g :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep).
                     g -> c g
                     -> Text -> c Text)
                @(forall (c :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep
                               -> TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep).
                  forall (d :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep)
                         (b :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep).
                  Data d => c (d -> b) -> d -> c b
                  -> forall (g :: TYPE ghc-prim-0.5.2.0:GHC.Types.LiftedRep).
                     g -> c g
                     -> T -> c T)
                gfoldl
      When typechecking the code for ‘gfoldl’
        in a derived instance for ‘Data T’:
        To see the code I am typechecking, use -ddump-deriv
      In the instance declaration for ‘Data T’

可能相关:GeneralizedNewtypeDeriving fails for PersistFieldSql

编辑:也许我应该只使用-XDeriveDataTypeable

【问题讨论】:

    标签: haskell ghc


    【解决方案1】:

    来自docs

    派生实例仅用于这些形式的声明 (任何类型同义词展开后):

    newtype T v1..vn                   = MkT (t vk+1..vn) deriving (C t1..tj)
    newtype instance T s1..sk vk+1..vn = MkT (t vk+1..vn) deriving (C t1..tj)
    

    在哪里 [...]

    • C 不是ReadShowTypeableData。这些类不应该“查看”类型或其构造函数。你仍然可以推导出这些 新类型的类,但它以通常的方式发生,而不是通过这个 新机制。与Default deriving strategy协商。

    重点是:newtypeData 实例应该根据 newtype 本身的构造函数来制作,而不是根据底层类型的(几个)构造函数来制作。

    一般化的newtype 实例只会将基础类型的Data 实例“强制”为newtype,但这是错误的。

    (不过,您收到的错误消息可能会更有帮助。)

    结论:尝试改用DeriveDataTypeable。这应该派生出正确的实例。

    newtype T = T Text deriving (Data)
    

    更准确地说,我们应该在适当的例子中看到这一点:

    > data U = A | B deriving Data
    > newtype T = T U deriving Data
    > toConstr (T A)
    T
    

    相反,“新类型派生”实例将在此处生成 A,公开底层构造函数,而不是预期的 T

    【讨论】:

    • 太好了,谢谢!你能扩展“不应该”的部分吗?我知道 Typeable 和朋友们确实想要创建类型的运行时表示。拥有一个简单地从派生对象继承此行为的实例(如果这是一个词)是完全非法的吗?我引入这种新类型(在我的具体情况下)的主要原因是通过区分 TText 从语言中挤出更多的类型安全性。
    • 涉及Generic 的案例是newtype Generically a = Generically a,它是Generic-behaviour 的包装器(将添加到GHC.Generics)。它的所有实例都从 Generic 继承了它们的行为,通过 newtype 派生它为 Generic 做同样的事情并不是不合理的。这通过避免包装和展开来简化其他实例。这是一个哲学问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-18
    • 2011-11-05
    • 2021-11-19
    • 2021-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多