8

如何确定 Haskell 类型在给定平台上是否具有等效的 Coercible 实例?

我刚刚在 GHC 7.8 中被告知Coercible,这似乎很棒。在这种情况下,我想解决我的具体问题的一个同样好的问题是:有没有办法询问 GHC 哪些类型对ab有一个Coercible a b实例(例如在当前平台上)?

在我看来,为了coerce :: Coercible a b => a -> b在与编译器和平台无关的程序中有用,需要知道——最好只在编译时,但也可能在编写代码时明确地知道——给定的Coercible a b实例是否存在于给定的平台上否则使用较慢的非noop回退(我猜是通过CPP)。

追问: GHC提供功能有意义吗

coerceOrConvert :: (a -> b) -> a -> b

与财产coerceOrConvert f

  • coerce如果有Coercible a b当前 GHC 版本和平台的实例

  • f如果不

我意识到这对于普通类型类来说意义不大,但Coercible似乎远非普通,所以我很难说……</p>

4

1 回答 1

5

通常,Haskell 中处理的强制类型有两种:表示相等(通过newtypeCoercible)和关于类型变量的新信息(通过Typeable)。第二种与运行时表示关系不大,所以我只描述Coercible/newtype机制。

这是保证newtype只改变类型信息而不是底层表示,因此如果我们有(标准示例)

newtype Age = Age { unAge :: Int }

那么我们应该能够对类似的东西充满信心

instance Num Age where
  Age a + Age b = Age (a + b)
  ...

(+)和on一样快Int——即幕后没有指针间接进行。事实上,GHC 在Age这里毫不费力地消除了构造函数。当我们想做类似的事情时,挑战就来了

map Age :: [Int] -> [Age]

因为Int和在结构上是相同的,所以这也应该是一个无操作——我们必须做的就是在编译时满足类型系统,然后在运行时在操作上Age丢弃。map Age可悲的是,情况并非如此,因为map即使它在每个阶段什么都不做,它仍然会遍历我们的列表。

在大量newtypes 被抛出但我们也希望 GHC 生成您可能会看到(危险的、小心的)使用的最紧凑的编译代码的情况下unsafeCoerce

unsafeCoerce :: [Int] -> [Age]

在这种情况下unsafeCoerce是“安全的”,因为我们知道这两种类型在运行时是相同的。此外,由于unsafeCoerce纯粹在类型级别上操作并且在运行时是真正的无操作,我们知道 like map Age,unsafeCoerce确实是一种O(0)强制。

但这非常危险。

Coercible希望通过允许像这样的实例化来解决这个问题

instance Coercible a b => Coercible [a] [b] where coerce = unsafeCoerce

因此 Haskell 类型类机器coerce只允许在安全时使用,不像unsafeCoerce. 为了确保这种情况,必须不可能构建恶意实例Coercible。为此,所有Coercible实例都是由编译器基于newtype.

最后一点,当您真正深入了解Coercible其工作原理时,您必须了解新的 Haskell 角色系统,该系统允许开发人员注释 a 是否newtype应该允许强制。这在 [Coercible类文档] ( http://www.haskell.org/ghc/docs/7.8.1-rc2/html/libraries/base-4.7.0.0/Data-Coerce.html ) 中有明确的概述。

于 2014-03-17T16:24:12.017 回答