考虑到unsafePerformIO,Haskell真的是一个纯函数式语言吗?
通常将Haskell引用为纯function语言的一个例子。 鉴于System.IO.Unsafe.unsafePerformIO
的存在,如何certificate这一点?
编辑:我认为“纯粹function”是指不可能将不纯的代码引入到程序的function部分。
我们称之为Haskell的语言
unsafePerformIO
是外部函数接口规范的一部分,而不是核心的Haskell 98规范。 它可以用来做局部的副作用,而不是逃避一些范围,以暴露纯粹的function接口。 也就是说,我们使用它来隐藏types检查器无法为我们做的事情(与ST monad不同,它隐藏了静态保证效果)。
为了精确地说明我们称之为“Haskell”的多种语言,请考虑下面的图片。 每个环对应于一组特定的计算特征,按照安全sorting,并且与expression能力相关的区域(即,如果具有该特征,则可以编写的程序数量)。
被称为Haskell 98的语言被指定在中间,承认全部和部分function。 Agda (或Epigram )只允许使用全部function,但performance力更弱,但“更纯粹”,更安全。 虽然今天我们使用Haskell包含了FFI的所有内容,而不安全的PerformaIO仍然存在。 也就是说,你可以在现代Haskell中写任何东西 ,但是如果你使用外圈的东西,那么通过内环就很难build立安全和安全的保证。
所以,Haskell程序通常不是由100%的引用透明的代码构build而成的,然而,它是默认情况下唯一适度的通用语言。
我认为“纯function”是指不可能引入不纯的代码。
真正的答案是unsafePerformIO
不是 Haskell的一部分,更不用说垃圾收集器或运行时系统是Haskell的一部分。 unsafePerformIO
中存在unsafePerformIO
,因此构build系统的人可以通过非常有效的硬件创build纯function抽象。 所有真正的语言都有漏洞,使得系统构build者可以用比C代码或汇编代码更有效的方式来完成工作。
关于副作用和I / O如何通过IO
monadembedded到Haskell中,我认为想想Haskell最简单的方法就是它是描述有效计算的纯粹语言。 当所描述的计算是main
,运行时系统忠实地执行这些效果。
unsafePerformIO
是一种以不安全的方式获得效果的方法; “不安全”的意思是“程序员必须保证安全” – 编译器无需检查。 如果你是一个精明的程序员,并愿意履行重要的certificate义务,你可以使用unsafePerformIO
。 但是在那个时候,你不再编程Haskell了。 你正在编写一个看起来很像Haskell的不安全的语言。
语言/实现是纯粹的function。 它包括一对“逃生舱”,如果不想使用,则不需要使用。
我不认为unsafePerformIO意味着haskell不知何故变得不纯洁。 您可以使用不纯的function创build纯粹的(引用透明的)function。
考虑跳过列表。 为了使其运行良好,它需要访问RNG,一个不纯的函数,但这不会使数据结构不纯。 如果添加一个项目,然后将其转换为列表,则每次给定添加的项目时都会返回相同的列表。
为此,我认为不安全的PERFORMIO应该被认为是promisePureIO。 一个函数,意味着具有副作用并因此被types系统标记为不纯的函数可以被types系统认可为引用透明。
我明白,你必须有一个稍微弱化的纯粹的定义。 即纯函数是引用透明的,并且由于副作用(如打印)而不会被调用。
不幸的是,语言必须做一些现实世界的工作,这意味着与外部环境谈话。
好处是你可以(也应该)将这种“风格”代码的使用限制在你的程序的几个特定的有证据的部分。
安全的Haskell,GHC最近的扩展,给这个问题一个新的答案。 unsafePerformIO
是GHC Haskell的一部分,但不是安全方言的一部分。
unsafePerformIO
只能用于构build引用透明的function; 例如记忆。 在这些情况下,包裹的作者将其标记为“值得信赖”。 安全模块只能导入安全可靠的模块; 它不能导入不安全的模块。
有关更多信息: GHC手册 , 安全Haskell纸张
我有一种感觉,说我要说什么,我会很不受欢迎,但是我觉得我必须回应一些(在我看来是错误的)信息。
虽然不安全的PERFORMIOIO作为FFI附录的一部分被正式添加到了该语言中,但其原因主要是历史性的而非逻辑性的。 它存在非正式的,早在Haskell有过FFI之前就被广泛使用。 它从来没有正式成为Haskell主要标准的一部分,因为正如你所看到的那样,这太尴尬了。 我想是希望在未来某个时候,它会在某种程度上消失。 那么没有发生,我的意见也不会。
FFI附录的发展为不安全的实施提供了一个便利的借口,因为它可能在这里看起来似乎不太糟糕,因为与增加调用外国(IE C)代码的能力(所有投注都是无论如何关于静态确保纯度和types安全)。 基于政治原因,把它放在这里也是非常方便的。 它促成了Haskell将是纯粹的神话,只要它不是那些肮脏的“糟糕的devise”,或者“糟糕的devise”的操作系统,或者“糟糕的devise”硬件或者任何东西。毫无疑问, unsafePerformIO经常与FFI相关的代码一起使用,但其原因通常更多的是与FFI的糟糕devise以及Haskell本身的devise有关,也不是Haskell正在尝试的外部事物的不良devise。
正如诺曼·拉姆齐(Norman Ramsey)所说,官方的立场是,使用unsafePerformIO是可以的,只要使用者能够满足某些certificate义务(主要是这样做不会使重要的编译器转换失效,如内联和常见的子expression式消除) 。 到目前为止这么好,或者可以这么想。 真正的挑战在于,这些certificate义务不能被可能是不安全的PerformaIOIO最常见的用例所满足,根据我的估计,这个用例大概占了所有非安全PerpetualIO的50%以上。 我正在谈论这个令人震惊的成语,称为“unsafePerformIO hack”,可以certificate(实际上显然)是完全不安全的 (在inline和cse中)。
我真的没有时间,空间或倾向去了解“unsafePerformIO黑客”是什么,或者为什么在真正的IO库中需要它,但底线是工作在Haskells IO基础设施上的人通常被困在摇滚和艰苦的地方“。 他们可以提供一个本质安全的API(在Haskell中没有安全的实现),或者他们可以提供一个固有的不安全的API,可以安全地实现,但是他们很less做的是提供APIdevise和实现的安全性。 从现实世界的代码(包括Haskell标准库)中出现的“unsafePerformIO hack”压抑的规律来看,似乎大多数select前者作为这两个弊端中的较小者,只希望编译器不会沉淀内联,cse或任何其他转换。
我希望所有这一切都不是这样。 不幸的是,