通常,Haskell 中处理的强制类型有两种:表示相等(通过newtype和Coercible)和关于类型变量的新信息(通过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 ) 中有明确的概述。