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

时间:2014-03-17 16:03:46

标签: haskell ghc representation coerce

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

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

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

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

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

具有coerceOrConvert f

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

  • f如果不是

我意识到这对于普通的类型类没什么意义,但是Coercible似乎很不平常,所以我很难说...

1 个答案:

答案 0 :(得分:5)

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

它保证newtype仅更改类型信息而不更改基础表示,因此如果我们有(标准示例)

newtype Age = Age { unAge :: Int }

那么我们应该能够对像

这样的东西充满信心
instance Num Age where
  Age a + Age b = Age (a + b)
  ...

(+)上的Int完全一样快 - 即。幕后没有指针间接。实际上,GHC在这里毫无困难地消除了Age构造函数。当我们想要做像

这样的事情时,就会面临挑战
map Age :: [Int] -> [Age]

因为IntAge在结构上是相同的,所以我们也应该是no-op ---我们必须做的就是在编译时满足类型系统然后扔掉{{1}在运行时运行。遗憾的是,情况并非如此,因为map Age仍将遍历我们的列表,即使它在每个阶段都没有做任何事情。

在大量map被抛出的情况下,我们也希望GHC生成最紧密的编译代码,您可能会看到(危险,谨慎)使用newtype

unsafeCoerce

在这种情况下,unsafeCoerce :: [Int] -> [Age] 是"安全"我们知道这两种类型的运行时完全相同。此外,由于unsafeCoerce纯粹在类型级别运行,并且在运行时是真正的无操作,我们知道与unsafeCoerce不同,map Age确实是unsafeCoerce强制。

但这很危险。

O(0)希望通过允许像

这样的实例来解决这个问题
Coercible

这样Haskell类型类机制允许instance Coercible a b => Coercible [a] [b] where coerce = unsafeCoerce 仅在安全时使用coerce。为了确保这种情况,不可能构建unsafeCoerce的恶意实例。为此,所有Coercible实例都是由编译器根据Coercible的使用而构建的。

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