具有可强制表示的Haskell类型与它们的C对应物相同吗?

gsp*_*spr 7 haskell representation ghc coerce

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

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

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

后续问题: GHC提供功能是否有意义

coerceOrConvert :: (a -> b) -> a -> b
Run Code Online (Sandbox Code Playgroud)

与该属性coerceOrConvert f

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

  • f 如果不

我意识到这对于普通的类型组来说没什么意义,但Coercible看起来很平常,所以我很难说...

J. *_*son 5

通常,Haskell中处理的强制类型有两种形式:表示等式(via newtypeCoercible)以及有关类型变量的新信息(via Typeable).第二种类型与运行时表示没什么关系,所以我只描述Coercible/ newtype机制.

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

newtype Age = Age { unAge :: Int }
Run Code Online (Sandbox Code Playgroud)

那么我们应该能够对这样的事情充满信心

instance Num Age where
  Age a + Age b = Age (a + b)
  ...
Run Code Online (Sandbox Code Playgroud)

(+)on 一样快Int- 就是幕后没有指针间接.实际上,GHC在Age这里毫无困难地消除了构造函数.当我们想要做类似的事情时,挑战就出现了

map Age :: [Int] -> [Age]
Run Code Online (Sandbox Code Playgroud)

因为Int并且Age在结构上是相同的,所以这也应该是一个无操作 - 我们必须做的就是在编译时满足类型系统,然后map Age在运行时丢弃操作.可悲的是,事实并非如此,因为map即使在每个阶段都没有做任何事情,遗嘱仍将遍及我们的名单.

在很多newtypes被抛出的情况下,我们也希望GHC生成最紧密的编译代码,你可能会看到(危险,小心)使用unsafeCoerce

unsafeCoerce :: [Int] -> [Age]
Run Code Online (Sandbox Code Playgroud)

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

但这很危险.

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

instance Coercible a b => Coercible [a] [b] where coerce = unsafeCoerce
Run Code Online (Sandbox Code Playgroud)

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

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