ChatGPT解决这个技术问题 Extra ChatGPT

参考透明度一词是什么意思?我听说它被描述为“这意味着你可以用 equals 替换 equals”,但这似乎是一个不充分的解释。

@claudia:我不能肯定地说,但 r/haskell 风起云涌,许多人认为 Uday 虽然相当准确,但在社区中受到了一点嘲笑。
@efrey 一个笑话,也许是。但是,当函数式程序员拒绝命令式编程语言和具有副作用的函数式语言(如 Lisp 和 ML)声称它们不是引用透明时,他们不是在嘲笑吗?他们不应该至少在这样做之前弄清事实吗?
@Claudiu 我一直在 Haskell Reddit 上发布它,而 Conal 一直在推特上发布它。我发现讨论很有趣,并认为值得进行更广泛的讨论。我提请注意乌代的嘲讽以激发讨论。我同意我们 FPers 有时会自满并需要一个好的刺激 - Uday 做得很好,因为它提供了它!
@efrey。确实,这就是为什么我在第二篇文章中选择引用 Bird 和 Wadler(语义学家?)的原因。知识渊博的人确实知道,引用透明度的流行概念是模糊的,可能是不连贯的。但它从未向编程社区正确解释过。希望我在这里的写作会有所作为。
@pedrorijo91 你读过 UdayReddy 的答案吗?他们解释了您的两个 FP 链接是如何错误的。 '[T] 早期语义学家所说的“价值”不是评估的结果,也不是函数或任何此类事物的输出。这是术语的外延。

J
Julian Chen

术语“参照透明性”来自analytical philosophy,这是一个基于逻辑和数学方法分析自然语言结构、陈述和论证的哲学分支。换句话说,它是计算机科学之外最接近我们所说的 programming language semantics 的学科。哲学家 Willard Quine 负责发起参照透明性的概念,但它也隐含在 Bertrand Russell 和 Alfred Whitehead 的方法中。

“参照透明”的核心是一个非常简单明了的概念。 “所指”一词在分析哲学中用于谈论表达式所指的事物。它与我们在编程语言语义中所说的“意义”或“外延”大致相同。使用 Andrew Birkett 的示例 (blog post),术语“苏格兰首都”指的是爱丁堡市。这是“参照物”的一个简单示例。

如果用引用同一实体的另一个术语替换该上下文中的术语不会改变含义,则句子中的上下文是“引用透明的”。例如

苏格兰议会在苏格兰首都开会。

意思是一样的

苏格兰议会在爱丁堡举行会议。

所以上下文“苏格兰议会在……开会”是一个参照透明的上下文。我们可以将“苏格兰的首都”替换为“爱丁堡”而不改变其含义。换句话说,上下文只关心该术语所指的内容,而不关心其他内容。这就是上下文“参照透明”的意义。

另一方面,在句子中,

爱丁堡自 1999 年以来一直是苏格兰的首都。

我们不能做这样的替换。如果我们这样做了,我们会得到“Edinburgh has been Edinburgh since 1999”,这是一个疯狂的说法,并且与原始句子的含义不同。因此,“爱丁堡自 1999 年以来一直是……”的上下文似乎在引用上是不透明的(与引用透明相反)。它显然关心的不仅仅是这个词所指的东西。它是什么?

诸如“苏格兰的首都”之类的东西被称为确定的术语,它们在很长一段时间内都没有让逻辑学家和哲学家感到头疼。 Russell 和 Quine 将它们整理出来,说它们实际上并不是“指代”,即认为上面的例子用来指代实体是错误的。理解“爱丁堡自 1999 年以来一直是苏格兰的首都”的正确方式是说

苏格兰自 1999 年以来就有了首都,首都是爱丁堡。

这句话不能变成一个疯狂的句子。问题解决了! Quine 的观点是说自然语言是混乱的,或者至少是复杂的,因为它是为了方便实际使用而设计的,但哲学家和逻辑学家应该通过以正确的方式理解它们来使它们变得清晰。参照透明性是一种用于使含义清晰的工具。

这一切与编程有什么关系?实际上,不是很多。正如我们所说,参照透明性是一种用于理解语言的工具,即分配含义Christopher Strachey,他创立了编程语言语义领域,在他的意义研究中使用了它。他的基础论文“Fundamental concepts in programming languages”可在网络上找到。这是一篇漂亮的论文,每个人都可以阅读和理解它。所以,请这样做。你会大开眼界。他在本段中介绍了“参照透明度”一词:

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

“本质上”的使用表明 Strachey 是在对其进行释义,以便用简单的术语来解释它。函数式程序员似乎以他们自己的方式理解这一段。论文中还有其他 9 处“引用透明性”,但它们似乎并不关心其他任何一个。事实上,Strachey 的整篇论文都致力于解释命令式编程语言的含义。但是,今天,函数式程序员声称命令式编程语言不是引用透明的。 Strachey 将在他的坟墓里翻身。

我们可以挽救局面。我们说自然语言是“杂乱无章的,或者至少是复杂的”,因为它是为了方便实际使用而设计的。编程语言也是如此。它们是“杂乱无章的,或者至少是复杂的”,因为它们被制作成便于实际使用。这并不意味着他们需要混淆我们。他们只需要以正确的方式被理解,使用一种引用透明的元语言,这样我们就有了清晰的含义。在我引用的论文中,Strachey 正是这样做的。他通过将命令式编程语言分解为基本概念来解释它们的含义,并且在任何地方都不会失去清晰度。他分析的一个重要部分是指出编程语言中的表达式有两种“值”,称为左值和右值。在 Strachey 的论文之前,人们不理解这一点,混乱占了上风。今天,C 的定义经常提到它,每个 C 程序员都明白其中的区别。 (其他语言的程序员是否同样理解它很难说。)

Quine 和 Strachey 都关心涉及某种形式的语境依赖的语言结构的意义。例如,我们的示例“爱丁堡自 1999 年以来一直是苏格兰的首都”表示“苏格兰的首都”取决于考虑它的时间这一事实。这种上下文依赖性在自然语言和编程语言中都是现实的。即使在函数式编程中,自由和绑定变量也要根据它们出现的上下文来解释。任何类型的上下文依赖都会以某种方式阻止引用透明性。如果你试图理解术语的含义而不考虑它们所依赖的上下文,你会再次陷入混乱。奎因关注模态逻辑的含义。他认为 modal logic 在引用上是不透明的,应该通过将其转换为引用透明的框架来清理它(例如,通过将必要性视为可证明性)。他在很大程度上输掉了这场辩论。逻辑学家和哲学家都发现克里普克的可能世界语义是完全足够的。命令式编程也存在类似的情况。 Strachey 解释的状态依赖和 Reynolds 解释的存储依赖(以类似于 Kripke 的可能世界语义的方式)是完全足够的。函数式程序员对这项研究了解不多。他们关于参照透明度的想法是不可取的。

[补充说明:上面的例子说明了一个简单的短语,如“苏格兰的首都”,具有多个层次的含义。在一个层面上,我们可能正在谈论当前的资本。在另一个层面上,我们可能会谈论苏格兰在一段时间内可能拥有的所有可能的首都。在正常实践中,我们可以很容易地“放大”特定的上下文并“缩小”以跨越所有上下文。自然语言的效率利用了我们这样做的能力。命令式编程语言以非常相似的方式高效。我们可以使用赋值右侧的变量 x(r 值)来讨论它在特定状态下的值。或者,我们可以谈论它跨越所有状态的 l 值。人们很少对这些事情感到困惑。然而,它们可能也可能无法准确解释语言结构中固有的所有含义层。所有这些层次的意义不一定是“显而易见的”,正确研究它们是科学问题。但是,普通人对这种分层含义的解释不清晰,并不意味着他们对此感到困惑。]

下面一个单独的“后记”将这个讨论与函数式和命令式编程的关注点联系起来。


谢谢,但我不认为存在“明显”的平等外延概念。当我说“苏格兰的首都”指的是爱丁堡市时,你没有三思而后行。但当我开始谈论“自 1999 年以来”时,你突然意识到其中涉及到时间。因此,平等的外延概念可能非常微妙,并且由编程语言研究人员将其形式化。想要完全理解外延平等的人需要学习这项研究的成果。它可能根本不是“显而易见的”。
极好的!对流行的关于 RT 的误解(例如,将其与功能联系起来)的一种可喜的解脱。或者通过用其值替换表达式来定义(如在维基百科上)——奇怪的是,因为表达式和值是不同种类的东西。也许人们在考虑命令式语言的 RT 特性时出错的一个地方是假设这些“值”是简单的东西,比如数字,而不是更复杂的东西,比如商店中的函数。
@sclv 至于分析哲学对计算机科学的更广泛影响,我应该说,众所周知,计算机科学是由 Godel、Church、Kleene 和 Turing 创立的。这些人是逻辑学家,他们精通逻辑的数学和哲学方面,特别是皮亚诺、弗雷格、罗素、怀特黑德、卡尔纳普和奎因的传统。现代计算机科学的早期先驱们知道其中的联系。但是计算机科学的快速发展已经切断了它们。我们需要回到他们身边。
@sclv 逻辑传统上被解释为后果科学。但我认为它的范围更广。它是信息科学。奎因,我认为是第一个提出更广泛观点的人。 “词与物”是对自然语言语句信息内容的分析。然而,无论是哲学家还是数学家都从未对计算产生过积极的兴趣,考虑到自古以来计算在文明和科学中的核心地位,这非常令人困惑。我们需要想办法让他们感兴趣。
@Conal:我添加了一个新答案,可以放大您的观点。它可能位于页面底部。
T
Tonio Liebrand

引用透明性是函数式编程中常用的一个术语,意味着给定一个函数和一个输入值,您将始终收到相同的输出。也就是说函数中没有使用外部状态。

下面是一个引用透明函数的例子:

int plusOne(int x)
{
  return x+1;
}

对于引用透明函数,给定一个输入和一个函数,您可以用一个值替换它而不是调用该函数。因此,我们可以将其替换为 6,而不是使用参数 5 调用 plusOne。

另一个很好的例子是一般的数学。在数学中,给定一个函数和一个输入值,它总是映射到相同的输出值。 f(x) = x + 1。因此数学中的函数是参照透明的。

这个概念对研究人员很重要,因为它意味着当您拥有一个引用透明的函数时,它可以轻松实现自动并行化和缓存。

引用透明性总是在像 Haskell 这样的函数式语言中使用。

--

相比之下,存在参照不透明性的概念。这意味着相反。调用函数可能并不总是产生相同的输出。

//global G
int G = 10;

int plusG(int x)
{//G can be modified externally returning different values.
  return x + G;
}

另一个例子是面向对象编程语言中的成员函数。成员函数通常对其成员变量进行操作,因此引用不透明。成员函数当然可以是引用透明的。

另一个示例是从文本文件读取并打印输出的函数。这个外部文本文件可以随时更改,因此该函数在引用上是不透明的。


请注意,可以拥有一个完全引用透明的对象,以及引用透明的成员函数。请参阅okmij.org/ftp/Scheme/oop-in-fp.txt
以下是那篇文章中讨论的代码:okmij.org/ftp/Scheme/pure-oo-system.scm
在完全引用透明类的情况下,您可能会将所有成员函数都设为静态。
您在这里谈论的不是参考透明度,尽管它通常被称为这样。请参阅 Uday 的两个答案以及对它们的评论。特别是,您所说的“输出”不是外延。如果您将“plusG 3”替换为具有相同值/表示的任何其他表达式,您确实会得到一个具有相同含义的程序,因此 RT 确实适用于命令式语言。表达式“3+10”或“13”与“plusG 3”的含义不同,因为命令式语言中的含义是“存储”(状态)的函数。
我刚刚阅读了一篇关于副作用和状态变化的文章,并直觉它与 RT 有关。你能在上面加个注释吗?
D
Draemon

引用透明函数是仅依赖于其输入的函数。


这就是为什么在 OO 编程中很难,因为对象有状态。
那么在描述函数时说“引用透明”与“确定性”相同是否正确?如果不是,这两个术语有什么区别?
这听起来也像是对“纯”函数的定义。
纯粹意味着没有副作用,我不认为引用透明度对此有任何要求。
@DharmaTurtle 有没有一个函数是纯函数但不是引用透明的例子?
U
Uday Reddy

[这是我 3 月 25 日回答的附言,旨在使讨论更接近函数式/命令式编程的关注点。]

函数式程序员的引用透明性的想法似乎在三个方面与标准概念不同:

哲学家/逻辑学家使用“reference”、“denotation”、“designatum”和“bedeutung”(弗雷格的德语术语)等术语,而函数式程序员使用“value”一词。 (这不完全是他们做的。我注意到,Landin、Strachey 和他们的后代也使用“价值”一词来谈论指称/外延。这可能只是 Landin 和 Strachey 引入的术语简化,但它似乎做了一个以幼稚的方式使用时有很大的不同。)

函数式程序员似乎相信这些“价值”存在于编程语言内部,而不是外部。在这样做时,他们不同于哲学家和编程语言语义学家。

他们似乎认为这些“价值”应该是通过评估获得的。

例如,今天早上 referential transparency 上的 Wikipedia 文章说:

如果一个表达式可以用它的值替换而不改变程序的行为(换句话说,产生一个在相同输入上具有相同效果和输出的程序),则称该表达式是引用透明的。

这与哲学家/逻辑学家所说的完全不同。他们说,如果上下文中的表达式可以被另一个引用同一事物的 表达式 替换(coreferential 表达式),则该上下文是引用或引用透明的。这些哲学家/逻辑学家是谁?它们包括 FregeRussellWhiteheadCarnapQuineChurch 和无数其他。他们每一个人都是一个巍峨的身影。这些逻辑学家的综合智力至少可以说是惊天动地的。他们都一致认为,指称/外延存在于形式语言之外,语言内的表达只能谈论它们。因此,在该语言中所能做的就是将一个表达式替换为另一个引用同一实体的表达式。指称/指称本身存在于语言中。为什么函数式程序员会偏离这个既定的传统?

人们可能会认为编程语言语义学家可能误导了他们。但是,他们没有。

Landin

(a) 每个表达式都有一个嵌套的子表达式结构,(b) 每个子表达式表示某些东西(通常是一个数字、真值或数值函数),(c) 一个表达式表示的东西,即它的“值”,仅取决于它的子表达式的值,而不是它们的其他属性。 [补充强调]

Stoy

表达式唯一重要的是它的值,并且任何子表达式都可以替换为任何其他值相等的[强调]。此外,表达式的值在一定范围内,无论何时出现都是相同的”。

Bird and Wadler

表达式的值仅取决于其组成表达式(如果有的话)的值,并且这些子表达式可以被具有相同值的其他表达式自由替换[强调]。

因此,回想起来,Landin 和 Strachey 通过用“价值”代替“参考”/“外延”来简化术语的努力可能是不明智的。一旦听到“价值”,就会很容易想到导致它的评估过程。将评估产生的任何东西视为“价值”同样很诱人,尽管很明显这不是外延。这就是我收集到的函数式程序员眼中的“引用透明”概念所发生的事情。但是早期语义学家所说的“价值”不是评估的结果,也不是函数的输出或任何类似的东西。这是术语的外延。

一旦我们将一个表达式的所谓“价值”(古典哲学家话语中的“指称”或“外延”)理解为一个复杂的数学/概念对象,各种可能性就会打开。

Strachey 将命令式编程语言中的变量解释为 L 值,正如我在 3 月 25 日的回答中提到的,这是一个复杂的概念对象,在编程语言的语法中没有直接表示。

他还解释了诸如状态到状态函数之类的语言中的命令,这是复杂数学对象的另一个实例,它不是语法中的“值”。

即使是 C 中的副作用函数调用也有一个明确定义的“值”,作为将状态映射到状态和值对的状态转换器(函数式程序员术语中的所谓“monad”)。

函数式程序员不愿将此类语言称为“引用透明”仅意味着他们不愿承认此类复杂的数学/概念对象为“值”。另一方面,他们似乎非常愿意将状态转换器称为“值”,当它被放入他们自己喜欢的语法并用像“monad”这样的流行词修饰时。我不得不说他们完全不一致,即使我们承认他们的“参考透明度”想法有一些连贯性。

一些历史可能会对这些混淆是如何产生的有所了解。 1962 年至 1967 年这段时间对克里斯托弗·斯特拉奇来说是一个非常密集的时期。 1962-65 年间,他在 Maurice Wilkes 担任兼职研究助理,负责设计和实现后来被称为 CPL 的编程语言。这是一种命令式编程语言,但也意味着具有强大的函数式编程语言功能。 Landin 是 Strachey 咨询公司的一名员工,对 Strachey 对编程语言的看法产生了巨大影响。在 1965 年具有里程碑意义的论文“Next 700 programming languages”中,Landin 毫不掩饰地推广函数式编程语言(称它们为外延语言)并将命令式编程语言描述为它们的“对立面”。在随后的讨论中,我们发现 Strachey 对 Landin 的强势地位提出了质疑。

... DL 构成所有语言的子集。它们是一个有趣的子集,但除非你习惯它,否则使用起来很不方便。我们需要它们,因为目前我们不知道如何使用包括命令式和跳转在内的语言构建证明。 [补充强调]

1965 年,Strachey 担任牛津大学的一名读者,似乎基本上全职致力于发展命令式和跳跃理论。到 1967 年,他准备好了一个理论,并在哥本哈根暑期学校的“Fundamental concepts in programming languages”课程中教授了该理论。讲义本应该发表,但“不幸的是,由于编辑拖沓,论文集从未实现;然而,与 Strachey 在牛津的大部分工作一样,该论文在私人发行量上颇具影响力。” (Martin Campbell-Kelly)

获得 Strachey 著作的困难可能导致混乱被传播,人们依赖二手资料和传闻。但是,既然“Fundamental concepts”在网络上很容易获得,就没有必要依靠猜测工作了。我们应该阅读它并自己决定 Strachey 的意思。尤其是:

在第 3.2 节中,他处理“表达式”,其中他谈到了“R 值引用透明度”。

他的第 3.3 节涉及“命令”,其中他谈到了“L 值引用透明度”。

在第 3.4.5 节中,他谈到了“函数和例程”,并声明“在 R 值上下文中 R 值引用透明度的任何偏离都应该通过将表达式分解为多个命令和更简单的表达式来消除,或者,如果事实证明这很困难,这是评论的主题。”

在不理解 L 值、R 值和填充命令式程序员的概念世界的其他复杂对象之间的区别的情况下,任何谈论“引用透明度”都是根本错误的。


我认为值得强调的是,混淆这两个“价值”概念(评估与表示)会误导函数式程序员对命令式语言的批评,其中概念之间的差距很大。
即,评估概念得出的结论是命令式语言不是 RT,而外延概念则不是。
在我看来,一旦你真正完全确定了一种语言的指称语义,它就会不由自主地成为参照透明的。所以这似乎等于说这个术语对编程语言没有用处。
因此,人们似乎习惯于使用一个术语来表示与其他人过去使用该术语时的含义大不相同的东西。我要说:欢迎使用英语。
@DanielPratt:如果无副作用是函数式程序员想要表达的意思,那么他们为什么称其为“引用透明性”?他们可以称之为“无副作用”,这是一个非常清晰的想法。没有人需要在 stackexchange 上询问“无副作用”是什么意思。哪里有必要盗用似乎没人理解的宏大经典术语?
C
Christian C. Salvadó

如果一个表达式可以用它的值替换,而不改变算法,则表达式是引用透明的,产生一个在相同输入上具有相同效果和输出的算法。


B
Barry Kelly

引用透明函数是一种类似于数学函数的函数。给定相同的输入,它总是会产生相同的输出。这意味着传入的状态没有被修改,并且函数没有自己的状态。


B
BenMorel

对于那些需要简明解释的人,我会冒险(但请阅读下面的披露)。

编程语言中的参照透明性促进了等式推理——参照透明性越高,执行等式推理就越容易。例如,使用(伪)函数定义,

fx = x + x,

在此定义的范围内,您可以(安全地)将 f(foo) 替换为 foo + foo 的容易程度,而无需对可以执行此缩减的位置有太多限制,这很好地表明了您的编程语言的引用透明度有。

例如,如果 foo 在 C 编程意义上是 x++,那么您将无法安全地执行此归约(也就是说,如果您要执行此归约,您最终不会得到与开始时相同的程序)。

在实际的编程语言中,您不会看到完美的引用透明性,但函数式程序员比大多数人更关心它(参见 Haskell,它是一个核心目标)。

(完全披露:我是一名函数式程序员,所以按照最重要的答案,你应该对这个解释持保留态度。)


我对促进等式推理的语言没有任何问题。但我认为它与经典定义的“参照透明度”有任何关系。其次,作为一个实用的程序员,我认为等式推理被高估了。在实践中重要的推理与前置条件、后置条件、不变量和数据抽象有关。对于依赖这种推理技术的人来说,副作用似乎并不重要。所以,虽然我同意你的观点,表达式中的副作用是一个坏主意,但它们似乎并不代表一个致命的论点。
@UdayReddy 仅仅因为函数式程序员选择了一种特殊的方法来提高程序中的引用透明度(消除副作用并开发复杂而强大的程序代数),或者有一些可能不了解引用透明度的从业者以及他们认为确实如此,但这并不意味着函数式编程语言未能提高引用透明度,或者函数式语言程序员和编译器编写者没有利用这种形式可处理性的增加来达到许多好的目的。
Chris:Uday 指出 Strachey 消除了编程语言语义中的引用不透明问题,特别是对于命令式语言。所以函数式程序员不能“在他们的程序中提高引用透明度”。作为一个具体的例子,Haskell IO 对 RT 没有帮助,因为不需要 RT 帮助。
@chrisdornan:对不起我上面的第一条评论。我自己很难理解我在前两句话中要说的内容:-(但是,这里有一个解释。考虑一个两级或多级分段演算。每个分段运算符在引用上都是不透明的。事实上, 引用运算符。但是,您可以在每个阶段内完美地进行等式推理。因此,每个引用不透明的运算符都为等式推理设置了边界。但是您仍然在这些边界内进行等式推理。
@chrisdomain:此外,很少有人愿意成为参考透明主义者,以驱逐此类临时操作员。这些运算符非常有用。在没有它们的情况下通过手动进行登台进行编程将是乏味的、容易出错的和丑陋的。而且,手动执行暂存不会比您之前拥有更多的等式推理。因此,在纯粹追求等式推理的过程中禁止使用好的编程设备就像是为了羞辱你的脸而割掉你的鼻子。
A
Andrew Birkett

如果您对词源感兴趣(即为什么这个概念有这个特定的名称),请查看我关于该主题的blog post。该术语来自哲学家/逻辑学家奎因。


A
Anuradha

指称语义基于建模语言,通过构建构成可指称值的域。函数式程序员使用术语值来描述基于语言重写规则的计算的收敛性,即。其操作语义。

在 1 中有两种语言的明确性:

被建模的对象语言

建模语言,元语言

2,由于对象和元语言的接近,它们可能会被混淆。

作为一名语言实现者,我发现我需要不断地记住这种区别。

所以雷迪教授可以这样解释你:-)

在函数式编程和语义的上下文中,术语参照透明不是参照透明的。


哈哈。感谢您的解释。问题还在于函数式程序员表现得好像他们有一个适用于所有编程语言的“引用透明性”的一般概念。但这取决于他们的“价值”概念,这对其他语言可能有意义,也可能没有意义。为了主张“参照透明”的一般理论,他们需要产生一般理论“价值”。到目前为止,这是缺失的。
佚名

我希望以下答案可以补充和限定有争议的第一个和第三个答案。

让我们承认一个表达式表示或指代某个指称对象。然而,一个问题是这些指示物是否可以同构地编码为表达式本身的一部分,称这些表达式为“值”。例如,文字数值是算术表达式集的子集,真值是布尔表达式集的子集,等等。这个想法是评估一个表达式的值(如果它有一个)。因此,“价值”这个词可能指代指称或一组表达式中的一个显着元素。但是,如果所指对象和值之间存在同构(双射),我们可以说它们是同一事物。 (这就是说,必须小心定义指称和同构,正如指称语义领域所证明的那样。举一个对第三个答案的答复中提到的例子,代数数据类型定义 data Nat = Zero | Suc Nat 与预期的不对应到自然数集。)

让我们将 E[·] 写成带有孔的表达式,在某些方面也称为“上下文”。类 C 表达式的两个上下文示例是 [·]+1[·]++

让我们将 [[·]] 表示为接受表达式(无孔)并在某个提供意义的宇宙中传递其意义(指称、外延等)的函数。 (我从指称语义学领域借用符号。)

让我们稍微正式地修改 Quine 的定义如下:上下文 E[·] 是指代透明的,当且仅当给定任何两个表达式 E1E2(那里没有漏洞)使得 [[E1]] = [[E2]](即表达式表示/引用相同的所指对象),那么 [[E[E1]]] = [[E[E2]]] 就是这种情况(即用 E1E2 填充孔会导致表达式也表示相同的所指对象)。

Leibniz 用equals 代替equals 的规则通常表示为“if E1 = E2 then E[E1] = E[E2]”,即E[·] 是一个函数。函数(或就此而言,计算函数的程序)是从源到目标的映射,因此每个源元素至多有一个目标元素。非确定性函数用词不当,它们要么是关系,要么是传递集合的函数,等等。如果在莱布尼茨规则中,等式 = 是指称的,那么双括号就被认为是理所当然的并被省略了。所以引用透明的上下文是一个函数。而莱布尼茨规则是等式推理的主要成分,所以等式推理肯定与参照透明有关。

虽然 [[·]] 是从表达式到外延的函数,但它可以是从表达式到“值”的函数,理解为表达式的受限子集,而 [[·]] 可以理解为求值。

现在,如果 E1 是一个表达式,而 E2 是一个值,那么我认为大多数人在定义表达式、值和评估方面的引用透明性时的意思。但正如本页第一个和第三个答案所示,这是一个不准确的定义。

[·]++ 等上下文的问题不是副作用,而是它的值在 C 中没有与其含义同构地定义。函数不是值(好吧,指向函数的指针是),而在函数式编程语言中它们是。 Landin、Strachey 和指称语义学的先驱们在使用功能世界来提供意义方面非常聪明。

对于命令式类 C 语言,我们可以(大致)使用函数 [[·]] : Expression -> (State -> State x Value) 为表达式提供语义。

ValueExpression 的子集。 State 包含对(标识符,值)。语义函数接受一个表达式,并将一个函数从当前状态传递给具有更新状态和一个值的对。例如,[[x]] 是从当前状态到第一个分量是当前状态,第二个分量是 x 值的对的函数。相反,[[x++]] 是从当前状态到第一个组件是 x 的值递增的状态,第二个组件是那个值的对的函数。从这个意义上说,上下文 [·]++ 是参照透明的,如果它满足上面给出的定义。

我认为函数式程序员有权使用引用透明性,因为他们自然地将 [[·]] 作为函数从表达式恢复到值。函数是一等值,状态也可以是一个值,而不是一个外延。状态单子(部分)是一种用于传递(或线程化)状态的干净机制。


大概“1st”和“3rd”的答案分别是 UdayReddy 的“March 25”和“postscript”的答案。序数不是在 SO 中引用答案的好方法。投票和接受不仅会随着时间的推移而变化,而且还有多个可选择的顺序。
Y
Yilmaz

当我阅读接受的答案时,我以为我在另一个页面上,而不是在 stackoverflow 上。

引用透明性是定义纯函数的一种更正式的方式。因此,如果一个函数在相同的输入上始终产生相同的结果,则称它是引用透明的。

let counter=0
function count(){
  return counter++
}

这不是引用透明的,因为返回值取决于外部变量“counter”并且它不断变化。

这就是我们如何使其引用透明:

function count(counter){
       return counter+1
   }

现在这个函数是稳定的,并且在提供相同的输入时总是返回相同的输出。


r
rdm

请注意,这个“意义”的概念是在观察者的脑海中发生的。因此,相同的“参考”对不同的人可能意味着不同的东西。因此,例如,我们在维基百科中有一个爱丁堡消歧页面。

可能出现在编程上下文中的一个相关问题可能是多态性。

也许我们应该为多态的特殊情况(甚至可能是强制转换)命名,其中不同的多态情况在语义上是等价的(而不仅仅是相似。例如,数字 1 - 可以表示使用整数类型、复杂类型或各种其他类型中的任何一种——可以多态处理)。


C
Can

参照透明性可以简单地表述为:

一个表达式在任何上下文 [1] 中总是计算相同的结果,

一个函数,如果给定两次相同的参数,则必须两次产生相同的结果 [2]。

例如,编程语言 Haskell 是一种纯函数式语言;意味着它是参照透明的。


A
Ari Fordsham

参照透明性是计算机科学中使用的一个术语。它起源于数理逻辑,但它在计算机科学中具有广泛的应用和有效的意义。

它的意思是:可以被其结果替换而不改变其含义的构造(例如函数)。

在一般使用中,它与纯表达式相似,但并不完全等价。纯表达式仅由其他纯表达式组成。引用透明的表达式可以是内部不纯的,例如在其计算过程中使用可变状态,但在整个表达式之外没有副作用。

所有纯函数,由于它们的构造,在引用上是透明的,但不一定反之亦然。

许多语言特性都支持不纯的引用透明性,例如 Haskell 中的 ST monad,以及 C++ 中的 constexpr 和某些 lambda。

有时会强制执行引用透明性,而有时程序员必须自己保证。