如何确定Haskell类型在给定平台上是否具有等效的Coercible实例?
我在GHC 7.8中被告知Coercible
,这看起来很棒。在这种情况下,我想解决我的具体问题一个同样好的问题是:有没有办法询问GHC关于哪些类型a
,b
有Coercible 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
似乎很不平常,所以我很难说...
答案 0 :(得分:5)
通常,Haskell中处理的强制类型有两种形式:表征式相等(通过newtype
和Coercible
)和有关类型变量的新信息(通过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]
因为Int
和Age
在结构上是相同的,所以我们也应该是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)中清楚地概述了这一点。