纯洁对抗参照透明度(计算机科学)

这两个术语看起来确实是不同的 定义,但我总是认为一个意味着另一个; 我想不出任何表达式是引用透明但不纯粹的情况,反之亦然。

维基百科为这些概念保留了单独的文章,并表示:

来自 参照透明度 (计算机科学):

中涉及的所有函数 表达式是纯函数 表达式是参照的 透明的。还有一些不纯净的 函数可以包括在 如果它们的值是 及其副作用 微不足道。

来自 纯粹的表情:

纯函数需要 构造纯粹的表达[ ... ]纯粹 表达式通常被称为 具有参照透明度。

我觉得这些陈述令人困惑。如果一个所谓的“不纯函数”的副作用是 微不足道,足以允许不执行它们(即用它的 价值替换对这样一个函数的调用)而不实质性地改变程序,这就好像它从一开始就是纯的一样,不是吗?

是否有更简单的方法来理解纯表达式和引用透明表达式(如果有的话)之间的区别?如果有区别的话,一个清楚地表明它的例子表达式会很受欢迎。

8882 次浏览

我有点不确定我在这里给出的答案,但肯定有人会给我们指出一些方向: -)

“纯度”通常被认为是指“缺乏副作用”。如果一个表达式的求值没有副作用,则称其为纯表达式。那副作用是什么?在纯函数式语言中,副作用是任何不遵循简单的 beta 规则的东西(评估函数应用程序的规则与用实际参数替代形式参数的所有自由出现的规则相同)。

例如,在具有线性(或唯一性,这种区别现在不应该打扰)类型的函数语言中,一些(受控的)变异是允许的。

所以我想我们已经弄清楚了什么是“纯度”和“副作用”。

参照透明度(计算机科学)(根据你引用的维基百科文章)意味着变量可以被它表示的表达式(缩写,代表)替换,而不改变手头程序的含义(顺便说一句,这也是一个很难解决的问题,我在这里不会尝试这么做)。因此,“纯度”和“参照透明度(计算机科学)”确实是不同的东西: “纯度”是某些表达式的属性,大致意思是“执行时不产生副作用”,而“参照透明度(计算机科学)”是与变量和表达式相关的属性,它所代表的意思是“变量可以用它所表示的东西取代”。

希望这能帮上忙。

所有纯函数都必然是引用透明的。因为根据定义,它们只能访问传递给它们的内容,所以它们的结果必须完全由它们的参数决定。

但是,有可能具有不纯粹的引用透明函数。我可以写一个函数,它给定一个整型 i,然后生成一个随机数 r,从中减去 r,放在 s中,然后返回 i - s。显然,这个函数是不纯的,因为它生成的是随机数。然而,它是指称透明的。在这种情况下,这个例子是愚蠢和人为的。然而,在 Haskell 中,id函数的类型是 a - > a,而我的 stupidId函数的类型是 a -> IO a,这表明它利用了副作用。当程序员可以通过外部证明的方式保证他们的函数实际上是引用透明的时候,他们就可以使用 unsafePerformIOr0从类型中剥离出来。

如果我把我认识的任何三位理论家聚集在一起,他们中至少有两位不同意“参照透明度(计算机科学)”一词的含义当我还是一个年轻的学生时,我的一位导师给了我一篇论文,解释说即使你只考虑专业文献,“参照透明”这个短语至少有三种不同的意思。(不幸的是,那张纸还在一盒重印本中的某个地方,还没有被扫描。我用谷歌学术搜索了一下,但是没有找到。)

我不能告诉你,但我建议你放弃: 因为即使是头脑简单的语言理论家的小骨干也不能同意它的意思,术语“参照透明”是 没用的。那就别用。


附注: 在任何与编程语言的语义有关的话题上,维基百科都是不可靠的。我已经放弃了修复它的努力; 维基百科的过程似乎把改变和公众投票看得比稳定性和准确性更重要。

我引用约翰 · 米切尔的话。他定义纯函数式语言必须通过声明式语言测试,即 没有副作用没有副作用

在 x1,... ,xn 的特定减速范围内,所有只包含变量 x1,... ,xn 的表达式 e 的出现都具有相同的值

在语言学中,如果一个名词或名词短语可以被具有相同指称的另一个名词短语替换而不改变它所包含的句子的意义,那么这个名词或名词短语就被认为是指称透明的。

在第一种情况下有效,但在第二种情况下就太奇怪了。

案例1: “我看到沃尔特进入了他的新

如果沃尔特拥有一个 Centro,那么我们可以在给定的句子中将其替换为:

“我看见 Walter 进入他的 中心

与第一点相反:

案例 # 2: 他被称为 William Rufus,因为他的阅读胡子。

鲁弗斯的意思是有点红,指的是英格兰的威廉四世。

“他被称为 威廉四世,因为他的阅读胡子。”看起来太尴尬。

传统的说法是,如果我们可以在不改变程序含义的情况下,在程序中的任何位置用一个等值的表达式替换另一个表达式,那么一种语言就是引用透明的。

所以参照透明度(计算机科学)是纯函数语言的一个特性。 如果您的程序没有副作用,那么这个属性将保持不变。

因此,放弃它是一个很棒的建议,但是在这种情况下也可能看起来不错。

这些来自 ACCU2015演讲 的幻灯片对参照透明度(计算机科学)的话题有很好的总结。

其中一张幻灯片上写道:

如果(a) ,则语言是引用透明的 每个子表达式都可以被其他子表达式替换 等于它的价值和(b)所有出现的 给定上下文中的表达式产生 一样的价值。

例如,可以有一个将其计算记录到程序标准输出的函数(因此,它不会是一个纯函数) ,但是可以用一个不记录其计算的类似函数替换对该函数的调用。因此,此函数具有 参照透明度 (计算机科学)属性。但是... ... 上面的定义是关于语言的,而不是幻灯片所强调的表达方式。

就像一开始是纯净的一样,不是吗?

从我们的定义来看,不,它不是。

是否有更简单的方法来理解纯表达式和引用透明表达式(如果有的话)之间的区别?

试试 我上面提到的幻灯片

标准的好处在于,它们有那么多可供选择 来自。

安德鲁·斯图尔特·塔能鲍姆。

还有参照透明度(计算机科学)的定义:

  • 作者: 伊恩 · 霍利尔(Ian Holyer):

    8.1价值观及行为

    纯函数式语言语义的最重要特性是,语言的声明性和操作性视图以下列方式完全一致:

    每个表达式都表示一个值,其中有一些值 < br > 对应于所有可能的程序行为。在任何上下文中由表达式产生的 < br > 行为完全由其值决定,反之亦然。

    这个原则通常被称为 参照透明度 (计算机科学),不透明,也可以用以下方式描述:

    picture of referential transparency

  • 以及来自 函数式编程语言中的不确定参照透明度(计算机科学)的 F · 沃伦 · 伯顿(F. Warren Burton) :

    [ ... ]表达式在相同环境中始终具有相同值的属性[ ... ]

... 其他各种定义,见 参照透明度(计算机科学)、确定性和不可折叠性作者: Harald Søndergaard 和 Peter Sestoft。

相反,我们将从“ 纯洁”的概念开始。对于你们三个还不知道的人来说,你们正在阅读这篇文章的计算机或设备是一台固态图灵机,一种与效果有着内在联系的计算模型。所以每个程序,不管是功能性的还是其他的,都需要使用这些效果来完成 TM

这对纯洁意味着什么?在汇编语言级别,也就是 CPU 的领域,所有的程序都是不纯粹的。如果你正在用汇编语言编写程序,你就是那个对所有这些效果之间的相互作用进行微观管理的人——它就是 太无聊了!

大多数时候,你只是指示 CPU 在计算机的内存中移动数据,这只会改变单个内存位置的内容——没什么好看的!只有当你的指令将 CPU 指向例如写入视频内存时,你才能观察到一个可见的变化(文本出现在屏幕上)。

出于我们在这里的目的,我们将效果分为两个粗略的类别:

  • 那些涉及 I/O 设备,如屏幕,扬声器,打印机,虚拟现实耳机,键盘,鼠标等; 通常称为 显而易见效应。
  • 剩下的只会改变记忆的内容。

在这种情况下,纯度仅仅意味着没有那些可观察到的影响,那些对正在运行的程序的环境造成可见的改变的影响,甚至可能是它的主机计算机。它肯定是 没有的所有效果的缺席,否则我们将不得不更换我们的固态图灵机!


现在,对于 42 生命,宇宙和一切这个术语“ 参照透明度 (计算机科学)”到底是什么意思的问题——与其说 放牧猫试图让理论家们达成一致,不如让我们试着找出这个术语的原始含义。幸运的是,这个术语经常出现在哈斯克尔的 I/o 上下文中——我们只需要一篇相关的文章... ..:

参照透明度(计算机科学)是指在不改变外部表达式的值的情况下,用等值的子表达式替换子表达式的能力。这个术语起源于奎因,由斯特雷奇引入计算机科学。

参考文献如下:

  • 来自克里斯托弗·斯特雷奇 程序设计语言中的基本概念的39页第9页:

    表达式最有用的属性之一就是奎因参照透明度(计算机科学)所调用的属性。从本质上说,这意味着如果我们希望找到一个包含子表达式的表达式的值,我们需要知道的关于子表达式的唯一事情就是它的值。子表达式的任何其他特征,例如其内部结构、组成部分的数量和性质、评估它们的顺序或书写它们的墨水的颜色,都与主要表达式的价值无关。

  • 威拉德 · 范 · 奥蒙德 · 奎因的 词与宾语:

    [ ... ]引用,从而中断了一个术语的参照力,可以说是参照 透明度2的失败。[ ... ]如果在一个术语或句子 Ψ(T)中单个术语 T的出现纯粹是指称的,那么在包含术语或句子 Φ (Ψ(T))中也纯粹是指称的,那么我称限制 Φ 的模式为指称透明。

    附注:

    这个术语来自怀特黑德和罗素,第2版,第1卷,第665页。

下文提到:

  • 《数学原理》的719页709阿尔弗雷德·诺思·怀特黑德和伯特兰·罗素:

    当一个断言发生时,它是通过一个特定的事实,这是一个命题的实例断言的手段。但是这个特殊的事实,可以说,是“透明的”; 没有任何关于它的说法,只是通过它来说一些关于其他东西的话。它是命题在真值函数中出现时所具有的“透明”性质。

让我们试着把这些都联系起来:

  1. 怀特海德和罗素引入了 “透明”这个术语;
  2. 奎因然后定义了限定术语 “参照透明度(计算机科学)”;
  3. 然后,Strachey 在定义编程语言的基础知识时采用了 Quine 的定义。

因此,这是奎因的原始定义还是 Strachey 的改编定义之间的选择。如果你愿意,你可以自己尝试翻译奎因的定义——每个曾经质疑过“ 纯粹是功能性的”定义的人甚至可能会有机会讨论一些不同的东西,比如“ 控制模式”和“ 纯粹是参考”到底是什么意思... ... 玩得开心!我们其他人只会接受斯特雷奇的定义有点模糊(“ 本质上[ ... ]”) ,然后继续:

表达式的一个有用的属性是参照透明度(计算机科学)。本质上,这意味着如果我们希望找到一个包含子表达式的表达式的值, 关于子表达式,我们唯一需要知道的是它的值。子表达式的任何其他特征,如其内部结构、数量和性质 它的组成部分,它们被评估的顺序或墨水的颜色,他们写,是无关的价值的主要表达。

(我强调)

关于这个描述(“ 如果我们希望找到[ ... ]”) ,Peter Landin 在 接下来的700种编程语言中给出了一个类似但更简洁的陈述:

一个表达式所表示的东西,也就是它的“值”,只取决于它的子表达式的 价值观,而不是它们的其他属性。

因此:

表达式的一个有用的属性是参照透明度(计算机科学)。本质上,这意味着一个表达式所表示的东西,也就是它的“值”,只取决于它的子表达式的 价值观,而不是它们的其他属性。

Strachey 举了一些例子:

  • (39页第12页)

    我们倾向于自动假设表达式(如3X2 + 2X + 17)中的符号 X在每次出现时表示相同的事物(或具有相同的值)。这是参照透明度(计算机科学)最重要的结果,只有利用这一特性,我们才能使用上一节描述的 where-子句或者 Λ表达式。

  • (第16页)

    当使用(或调用或应用)函数时,我们编写 F[ Ε] ,其中 Ε可以是一个表达式。如果我们使用的是引用透明语言,那么为了计算 F[ Ε] ,我们需要知道的关于表达式 Ε的所有信息就是它的值。

因此,根据斯特雷奇最初的定义,参照透明度(计算机科学)意味着纯度——在没有评估顺序的情况下,可观察到的和其他效果都是 差不多吧无用的... ..。

纯函数是那些在每次调用中返回相同值且没有副作用的函数。

参照透明度(计算机科学)意味着你可以用它的值替换一个绑定的变量,并且仍然可以得到相同的输出。

纯粹透明和参照透明:

def f1(x):
t1 = 3 * x
t2 = 6
return t1 + t2

为什么是纯的?

因为它只是输入 x的函数,没有副作用。

为什么这是透明的?

您可以用 return语句中各自的右边来替换 f1中的 t1t2,如下所示

def f2(x):
return 3 * x + 6

在任何情况下,f2仍然会返回与 f1相同的结果。

纯粹,但不具有参照透明度:

让我们修改 f1如下:

def f3(x):
t1 = 3 * x
t2 = 6
x = 10
return t1 + t2

让我们再试一次同样的把戏,把 t1t2换成它们的右边,看看它们是否是 f3的等价定义。

def f4(x):
x = 10
return 3 * x + 6

我们可以很容易地观察到 f3f4在用它们的右边/值替换变量时是不等价的。f3(1)将返回 9f4(1)将返回 36

参照透明,但不纯粹 :

只需修改 f1以接收非本地值 x,如下所示:

def f5:
global x
t1 = 3 * x
t2 = 6
return t1 + t2

执行相同的替换练习从前表明,f5仍然是参照透明的。但是,它不是纯的,因为它不仅仅是传递给它的参数的函数。

仔细观察,我们失去参照透明度(计算机科学)从 f3移动到 f4的原因是因为 x被修改了。在一般情况下,创建一个变量 final(或者那些熟悉 Scala 的人,使用 vals 而不是 vars)和使用不可变对象可以帮助保持函数的引用透明性。这使得它们更像是 代数或者 数学意义上的变量,因此更适合形式验证。