有时候,如果没有至少一种语言扩展名,我想写的一段代码就不合法。当试图在研究论文中实现这些想法时尤其如此,这些论文倾向于使用在撰写论文时可用的任何spiffy,超扩展版本的GHC,而没有明确实际需要哪些扩展。
结果是我经常在我的.hs文件顶部找到类似的东西:
{-# LANGUAGE TypeFamilies
, MultiParamTypeClasses
, FunctionalDependencies
, FlexibleContexts
, FlexibleInstances
, UndecidableInstances
, OverlappingInstances #-}
我不介意,但我常常觉得我在做出盲目的牺牲来安抚GHC的大神。它抱怨没有语言扩展X,某段代码无效,所以我为X添加了一个pragma。然后它要求我启用Y,所以我为Y添加了一个pragma。到这个时候,我已经启用三个或四个我不太了解的语言扩展,我不知道哪些是“安全的”。
用“安全”来解释我的意思:
我理解UndecidableInstances
是安全的,因为虽然它可能会导致编译器无法终止,但只要代码编译它就不会产生意想不到的副作用。
另一方面,OverlappingInstances
显然不安全,因为它使我很容易意外地编写导致运行时错误的代码。
所以我的问题是:
是否有GHCextensions列表被认为是“安全的”且“不安全”?
答案 0 :(得分:39)
最好看一下SafeHaskell允许的内容:
安全语言
安全语言(通过
-XSafe
启用)以两种不同的方式限制事物:
- 完全不允许使用某些GHC LANGUAGE扩展名。
- 某些GHC LANGUAGE扩展功能受限。
醇>以下是每个类别中的标记和扩展名:
- 完全禁止:
GeneralizedNewtypeDeriving
,TemplateHaskell
- 受限制的功能:
OverlappingInstances
,ForeignFunctionInterface
,RULES
,Data.Typeable
- 请参阅下面的受限制功能
- 无关紧要:所有剩余的旗帜。
限制和禁用GHC Haskell功能
在安全语言方言中,我们限制以下Haskell语言功能:
ForeignFunctionInterface
:这大多是安全的,但是不允许导入非IO类型的函数的外部导入声明。所有FFI导入必须位于IO Monad中。RULES
:由于他们可以用意想不到的方式改变可信代码的行为,违反了语义一致性,因此它们在功能上受到限制。具体而言,在使用RULES
编译的模块M
中定义的任何-XSafe
都将被删除。RULES
在可靠模块中定义,M
导入仍然有效,并将照常启动。OverlappingInstances
:此扩展可用于违反语义一致性,因为恶意代码可以通过更改导入不受信任模块的代码行为的方式重新定义类型实例(通过包含更具体的实例定义)。对于使用M
编译但受限制的模块-XSafe
,不会禁用该扩展名。虽然M
可以定义重叠的实例声明,但它们只能在M
中使用。如果在导入N
的模块M
中,在使用类型类函数的调用站点上,可以选择使用哪个实例(即重叠),最具体的选择来自{{ 1}}(或任何其他安全编译模块),然后编译将失败。如果模块M
被认为是安全的或可靠的或两者都不相关则无关紧要。N
:我们允许派生Data.Typeable
的实例,但我们不允许手工制作的实例。派生的实例是由GHC生成的机器,应该是非常安全的,但是手工制作的实例可能与其类型有关,并允许类型之间的不安全强制。这符合SYB原创设计的精神。在安全语言方言中,我们完全禁用了以下Haskell语言功能:
Data.Typeable
:它可以用来违反构造函数访问控制,允许不受信任的代码以数据类型作者不想要的方式操作受保护的数据类型。我可以用来打破数据结构的不变量。GeneralizedNewtypeDeriving
:特别危险,因为它甚至可以在编译时引起副作用,并可用于访问抽象数据类型。用TH打破模块边界非常容易。
我记得曾经读过TemplateHaskell
和FunctionalDependencies
的互动也可能不安全,因为除了允许无限制的上下文堆栈深度UndecidableInstances
之外,还会提升所谓的coverage condition (第7.6.3.2节),但我现在找不到这个。
编辑2015-10-27:自GHC获得类型角色支持以来,UndecidableInstances
已不再不安全。 (我不确定还有什么可能改变。)