来自GHC的手册,第Safe Language节:
模块边界控制 - 使用安全语言编译的Haskell代码保证只能访问通过其他模块导出列表公开使用的符号。其中一个重要的部分是安全编译的代码无法使用无法导入的数据构造函数来检查或创建数据值。如果模块M通过仔细使用其导出列表建立了一些不变量,则使用导入M的安全语言编译的代码保证遵守这些不变量。因此,我们会使用安全语言禁用模板Haskell和
GeneralizedNewtypeDeriving
,因为它们可能会违反此属性。
如何使用GeneralizedNewtypeDeriving
打破模块的不变量?
答案 0 :(得分:27)
Luqui与my blog post有关。基本上,GHC中实现的GeneralizedNewtypeDeriving
假设某种同构(即newtype
隐含的操作上无关的同构)意味着莱布尼茨相等。这在Haskell 98中是正确的 - 但在Haskell plus扩展中根本不是 true。
也就是说,newtype提供了一对函数
a -> b
b -> a
在核心中没有做任何事情,但不能总结
forall f. f a -> f b
因为f
可能是类型函数或GADT。这是GeneralizedNewtypeDeriving
即使在Haskell 98中,它也会打破模块边界。你可以拥有像
这样的东西class FromIntMap a where
fromIntMap :: Map Int b -> Map a b
instance FromIntMap Int where
fromIntMap = id
newtype WrapInt = WrapInt Int deriving FromIntMap
instance Ord WrapInt where
WrapInt a <= WrapInt b = b <= a
会做坏事......
我的博客文章展示了如何使用其他扩展程序(所有安全)以及unsafeCoerce
实现GeneralizedNewtypeDeriving.
几种方式。我对现在的原因有了更好的理解,并对{{1}更加自信如果没有“System FC”样式扩展(类型为familes,GADT),则无法生成GeneralizedNewtypeDeriving
。 Sill,它是不安全的,如果有的话应该小心使用。我的理解是Lennart Augustsson(用户augustss)在hbc中实现它的方式非常不同,这种实现是安全的。安全的实施将更加有限,而且更加复杂。
更新:使用足够新版本的GHC(从7.8.1开始,所有问题都应该消失)unsafeCoerce
由于新的roles system