【问题标题】:How do phantom types work with newtype?幻像类型如何与 newtype 一起使用?
【发布时间】:2013-11-09 00:36:50
【问题描述】:

我对新类型的理解是它们是由 GHC 编译出来的。然而,这不可能是全部,因为幻像类型可以保存信息。

来自here

您可以将 [a type] 包装在 newtype 中,它会被认为与类型检查器不同,但在运行时相同。然后,您可以使用各种深层技巧,例如幻像或递归类型,而无需担心 GHC 会无缘无故地对字节桶进行洗牌。

例如,想象一个表示算术模 q 的新类型:

newtype Zq q = Zq Int

class Modulus q where
    getModulus :: q -> Int

addZq :: (Modulus q) => Zq q -> Zq q -> Zq q
addZq (Zq a) (Zq b) = Zq $ (a+b) `mod` (getModulus (undefined :: q))

addZq 无法编译为

addZq :: Int -> Int -> Int

那么 newtype 是在什么意义上编译出来的,幻像类型信息存储在哪里?

【问题讨论】:

    标签: haskell newtype phantom-types


    【解决方案1】:

    要记住的是,不要“编译”到 Haskell;你编译成其他更明确的语言——在 GHC 的例子中,下一个众所周知的步骤是核心。尽管您不能在 Core 中将 addZq 编译为 Int -> Int -> Int 类型,但您可以将其编译为您可能写为 Modulus q => Int -> Int -> Int 的类型。在这种更明确的语言中,=> 与 Haskell 中的含义不同;在这种语言中,c => t 是一个函数的类型,它为声明 c 获取证据(在本例中为类字典)并产生 t 类型的东西。所以Modulus q => Int -> Int -> Int(q -> Int) -> Int -> Int -> Int 大致相同,而且addZq 当然可以被赋予这种类型,即使在Haskell 中也是如此。

    【讨论】:

    • 再往下走,“大致”相同变成完全相同。请参阅reflection 包,了解如何通过此作弊来解决 Haskell 缺乏运行时生成实例的问题。
    【解决方案2】:

    当新类型被 GHC 编译出来时,这仅意味着运行时行为。具体来说,保证它们不会比没有newtype 的相同代码慢。但它们仍然在整个编译过程中携带类型信息,包括用作幻像类型时。

    换句话说,新类型只是编译时信息,这足以让幻象类型工作。

    【讨论】:

      猜你喜欢
      • 2019-12-10
      • 2014-12-23
      • 1970-01-01
      • 2010-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-12
      • 2019-08-29
      相关资源
      最近更新 更多