微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

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

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

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

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

与coerceOrConvert f的属性

>如果当前的GHC版本和平台存在Coercible a b实例,则强制执行
> f如果没有

我意识到这对于普通的类型组来说没什么意义,但是Coercible似乎远非普通,所以我很难说…

解决方法

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

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

newtype Age = Age { unAge :: Int }

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

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

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

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

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

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

unsafeCoerce :: [Int] -> [Age]

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

但这很危险.

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

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

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐