37

有时,如果没有至少一个语言扩展,我想编写的一段代码是不合法的。当试图在研究论文中实现想法时尤其如此,这些论文倾向于使用撰写论文时可用的任何漂亮的、超扩展的 GHC 版本,而没有明确说明实际需要哪些扩展。

结果是我经常在 .hs 文件的顶部得到类似这样的内容:

{-# LANGUAGE TypeFamilies
           , MultiParamTypeClasses
           , FunctionalDependencies
           , FlexibleContexts
           , FlexibleInstances
           , UndecidableInstances
           , OverlappingInstances #-}

我不介意,但我常常觉得我在做盲目的牺牲来安抚GHC的大神。它抱怨某段代码在没有语言扩展 X 的情况下无效,所以我为 X 添加了一个 pragma。然后它要求我启用 Y,所以我为 Y 添加一个 pragma。到这完成时,我已经启用三四种我不太了解的语言扩展,我不知道哪些是“安全的”。

解释我所说的“安全”是什么意思:

  • 我知道这UndecidableInstances是安全的,因为尽管它可能导致编译器不终止,但只要代码编译它就不会产生意外的副作用。

  • 另一方面,OverlappingInstances显然是不安全的,因为它让我很容易意外地编写出运行时错误的代码。

所以我的问题是:

是否有被认为是“安全”和“不安全”的 GHC 扩展列表?

4

1 回答 1

39

最好看看SafeHaskell允许什么:

安全语言

安全语言(通过 启用-XSafe)以两种不同的方式限制事物:

  1. 完全不允许某些 GHC LANGUAGE 扩展。
  2. 某些 GHC LANGUAGE 扩展在功能上受到限制。

以下正是属于每个类别的标志和扩展:

  • 完全禁止:GeneralizedNewtypeDeriving,TemplateHaskell
  • 受限功能:OverlappingInstances, ForeignFunctionInterface, RULES,Data.Typeable
    • 请参阅下面的受限功能
  • 没关系:所有剩余的标志。

受限和禁用的 GHC Haskell 功能

在安全语言方言中,我们限制了以下 Haskell 语言功能:

  • ForeignFunctionInterface:这主要是安全的,但是不允许使用非 IO 类型导入函数的外部导入声明。所有 FFI 导入必须驻留在 IO Monad 中。
  • RULES:因为它们可以以意想不到的方式改变受信任代码的行为,违反语义一致性,它们在功能上受到限制。具体来说,在编译RULES的模块中定义的任何内容都将被删除。在值得信赖的模块中定义导入仍然有效并且会照常触发。M-XSafeRULESM
  • OverlappingInstances:此扩展可用于违反语义一致性,因为恶意代码可以重新定义类型实例(通过包含更具体的实例定义),从而改变导入不受信任模块的代码的行为。M对于使用编译-XSafe但受限制的模块,扩展不会被禁用。虽然M可以定义重叠的实例声明,但它们只能用于M. 如果在N导入的模块中M,在使用类型类函数的调用站点可以选择使用哪个实例(即重叠)并且最具体的选择来自M(或任何其他安全编译模块),那么编译将失败。N模块是否被认为是安全的、可信赖的或两者都不是,这无关紧要。
  • Data.Typeable:我们允许Data.Typeable派生的实例,但我们不允许手工制作的实例。派生实例是由 GHC 机器生成的,应该是完全安全的,但手工制作的实例可能会谎报其类型并允许类型之间的不安全强制。这符合 SYB 原始设计的精神。

在安全语言方言中,我们完全禁用了以下 Haskell 语言功能:

  • GeneralizedNewtypeDeriving:它可用于违反构造函数访问控制,允许不受信任的代码以数据类型作者不打算的方式操作受保护的数据类型。即可以用来打破数据结构的不变量。
  • TemplateHaskell: 特别危险,因为即使在编译时也会产生副作用,并且可用于访问抽象数据类型。使用 TH 很容易打破模块边界。

FunctionalDependencies我记得曾经读过and的交互UndecidableInstances也可能是不安全的,因为除了允许无限的上下文堆栈深度之外,UndecidableInstances还提升了所谓的覆盖条件(第 7.6.3.2 节),但我目前找不到这个引用.

编辑 2015-10-27:自从 GHC 获得对类型角色GeneralizedNewtypeDeriving的支持以来,不再不安全。(我不确定还有什么可能发生的变化。)

于 2012-05-31T10:22:49.200 回答