标记模块Safe
是否有不利之处?应该是默认值吗?
答案 0 :(得分:6)
您可以在GHC user manual中阅读,如果您标记模块Safe
,则只能使用Haskell语言的某个“安全”子集。
Safe
的模块(排除了unsafeCoerce
或unsafePerformIO
之类的功能)。IO
之外使用FFI。GeneralisedNewtypeDeriving
。Generic
类型类。作为交换,模块的用户获得了很多保证(从手册中引用):
- 引用透明性-可以信任的类型。任何纯函数,都保证是纯函数。评估它们是确定性的 并且不会造成任何副作用。
IO
monad中的功能仍然 允许并像往常一样表现。因此,例如,unsafePerformIO :: IO a -> a
函数在安全语言中是不允许执行的 财产。- 模块边界控制-只有在其他模块导出列表中公开可用的符号才能在保险箱中访问 语言。使用未由定义导出的数据构造函数的值 模块,无法检查或创建。因此,如果模块
M
通过谨慎使用其导出列表来确定一些不变式, 然后保证以安全的语言编写的代码导入M
尊重那些不变性。- 语义一致性-对于导入以安全语言编写的模块的任何模块,使用和不使用编译的表达式 在两种情况下,安全导入的含义相同。那是, 导入以安全语言编写的模块无法更改 不依赖于该模块的现有代码的含义。因此对于 例如,在使用上有一些限制
OverlappingInstances
,因为它们可能会违反此属性。- 严格的子集-安全语言严格来说是GHC实施的Haskell的子集。使用安全语言编译的任何表达式 与在普通的Haskell中进行编译的含义相同。
请注意,可以推断出安全性。如果您的模块未标记有Safe
,Trustworthy
或Unsafe
中的任何一个,则GHC会将模块的安全性推断为Safe
或Unsafe
。当您设置Safe
标志时,如果GHC认为模块实际上并不安全,它将发出一个错误。您还可以设置-Wunsafe
,如果推断出模块不安全,则会发出警告。如果您推断出它,即使您的依赖项的安全状态发生了变化,您的模块也将继续编译。如果将其写出,则向用户保证安全状态稳定可靠。
手册中描述的一个用例是运行“不受信任”的代码。如果您在产品中提供了任何种类的扩展点,并且要确保不使用这些功能来攻击产品,则可以要求将扩展点的代码标记为Safe
。
您可以标记模块Trustworthy
,这在实现模块时不会以任何方式限制您。然后可以从Safe
代码中使用您的模块,并且您有责任不违反保证,而该保证应由Safe
代码给出。所以,这是一个承诺,您是上述模块的作者,应该给予。在编译here中描述为标记为-fpackage-trust
的模块时,可以使用标志Trustworthy
启用额外的检查。
因此,如果您编写普通的库并且没有充分的理由关心Safe Haskell,那么您可能就不需要关心。如果您的模块是安全的,那很好,可以推断出来。如果不是,那么这可能是有原因的,例如因为您使用了unsafePerformIO
,这也很好。如果您知道您的模块将以某种要求其在-XSafe
下进行编译的方式使用(例如,如上所述的插件),则应该这样做。在其他所有情况下,请不要打扰。