参照透明性一词是什么意思?我听说它被描述为“这意味着您可以用相等替换相等”,但这似乎是一个不足的解释。
参照透明性一词是什么意思?我听说它被描述为“这意味着您可以用相等替换相等”,但这似乎是一个不足的解释。
Answers:
术语“参照透明性”来自分析哲学,这是哲学的分支,它基于逻辑和数学方法分析自然语言的构造,陈述和论点。换句话说,它是计算机科学之外最接近我们所谓的编程语言语义学的主题。哲学家威拉德·奎因(Willard Quine)负责提出参照透明性的概念,但在伯特兰·罗素(Bertrand Russell)和阿尔弗雷德·怀特黑德(Alfred Whitehead)的研究方法中也隐含了这一点。
从本质上讲,“参照透明”是一个非常简单而清晰的想法。在分析哲学中,术语“指代物”用于谈论表达式所指的东西。它与我们在编程语言语义中所说的“含义”或“表示”大致相同。以安德鲁·伯克特(Andrew Birkett)的例子(博客文章)为例,“苏格兰的首都”一词指的是爱丁堡市。那是“指称”的简单例子。
如果用引用同一实体的另一个术语替换上下文中的术语,则该句子中的上下文是“相对透明的” 。例如
苏格兰议会在苏格兰首都举行会议。
与...相同
苏格兰议会在爱丁堡举行会议。
因此,“苏格兰议会在……开会”这一上下文是参照透明的上下文。我们可以用“爱丁堡”代替“苏格兰的首都”,而无需改变含义。换句话说,上下文仅关心该术语所指的内容,而无所谓。这就是上下文“相对透明”的意义。
另一方面,在句子中
自1999年以来,爱丁堡一直是苏格兰的首都。
我们不能做这样的替换。如果这样做的话,我们将得到“爱丁堡自1999年以来就是爱丁堡”的说法,这是胡说八道,并不传达与原始句子相同的含义。因此,上下文“爱丁堡自1999年以来……”是参照透明的(与参照透明相反)。显然,它关心的不仅仅是该术语所指的东西。它是什么?
诸如“苏格兰首都”之类的事物被称为定冠词,它们在很长一段时间内都没有给逻辑学家和哲学家带来任何头痛。罗素(Russell)和奎因(Quine)对它们进行了分类,说它们实际上不是“引用”,即认为上述示例用于引用实体是错误的。理解“爱丁堡自1999年以来就是苏格兰的首都”的正确方法是
苏格兰自1999年以来就有首都,而首都是爱丁堡。
这句话不能转化为坚果味。问题解决了!Quine的意思是说,自然语言是杂乱的,或者至少是复杂的,因为它使语言易于实际使用,但是哲学家和逻辑学家应该以正确的方式理解它们,以使其清晰。参照透明性是一种用于带来这种意义清晰的工具。
这一切与编程有什么关系?实际上不是很多。如前所述,参照透明性是一种用于理解语言(即分配含义)的工具。 创立编程语言语义学领域的Christopher Strachey将其用于意义研究中。他的基础论文“ 编程语言的基本概念 ”可以在网上找到。这是一篇漂亮的论文,每个人都可以阅读和理解。所以,请这样做。您将大开眼界。他在本段中引入了“参照透明性”一词:
表达式最有用的属性之一是Quine引用透明性所调用的属性。从本质上讲,这意味着如果我们希望找到包含子表达式的表达式的值,那么关于子表达式我们唯一需要了解的就是它的值。子表达式的任何其他特征,例如其内部结构,其组成部分的数量和性质,评估它们的顺序或书写它们的墨水颜色,均与主体的值无关。表达。
“本质上”的使用表明Strachey对其释义,以便用简单的术语进行解释。函数式程序员似乎以自己的方式理解本段。本文中还有9个“参照透明性”的出现,但它们似乎并不在乎其他任何一个。实际上,Strachey的整个论文都致力于解释命令式编程语言的含义。但是,今天,函数式程序员声称命令式编程语言不是引用透明的。Strachey会在坟墓里转弯。
我们可以挽救局势。我们说自然语言是“混乱的,或者至少是复杂的”,因为它使实用方便。编程语言是相同的方式。它们是“混乱的,或至少是复杂的”,因为它们被制成便于实际使用。这并不意味着他们需要使我们感到困惑。只需要使用一种引用透明的元语言就可以正确地理解它们,以便我们清楚地理解含义。在我引用的论文中,Strachey正是这样做的。他通过将命令式编程语言分解为基本概念来解释命令式编程语言的含义,从不丧失任何地方的清晰度。他的分析的重要部分是指出编程语言中的表达式具有两种“值”,r值。在Strachey的论文发表之前,这还不为人所知,混乱至高无上。如今,C的定义已定期提及它,并且每个C程序员都理解这一区别。(很难说其他语言的程序员是否同样理解它。)
Quine和Strachey都关心涉及某种形式的上下文相关的语言构造的含义。例如,我们的示例“爱丁堡自1999年以来一直是苏格兰的首都”表明“苏格兰的首都”取决于考虑该城市的时间这一事实。无论是自然语言还是编程语言,这种上下文相关性都是现实。即使在函数式编程中,自由变量和绑定变量也要针对它们出现的上下文进行解释。任何种类的上下文相关性都会以某种方式阻止参照透明性。如果您在不考虑术语所依赖的上下文的情况下尝试理解术语的含义,则会再次陷入混乱。Quine关心模态逻辑的含义。他认为模态逻辑是参照不透明的,应通过将其转换为参照透明的框架(例如,将必要性视为可证明性)进行清理。他很大程度上失去了这场辩论。逻辑学家和哲学家都发现,克里普克的可能世界语义学是完全合适的。强制性编程也存在类似情况。Strachey解释的状态依赖和Reynolds解释的存储依赖(以与Kripke可能的世界语义类似的方式)完全足够。函数式程序员对此研究并不了解。他们关于参照透明性的想法要花大量的盐。
[附加说明:以上示例说明了一个简单的词组,例如“苏格兰首都”,具有多种含义。一方面,我们可能正在谈论当前的资本。在另一个层面上,我们可能会谈论苏格兰在一段时间内可能拥有的所有可能的首都。在正常实践中,我们可以“放大”特定的上下文,并“缩小”以轻松跨越所有上下文。自然语言的效率利用了我们的能力。命令式编程语言以几乎相同的方式有效。我们可以在赋值(r值)的右侧使用变量x来讨论其在特定状态下的值。或者,我们可能会谈论它的L值跨越所有州。人们很少被这种事情弄糊涂。但是,他们可能无法也可能无法准确地解释语言构造所固有的所有含义层。所有这些含义层不一定都是“显而易见的”,正确研究它们是科学问题。但是,普通人解释这种分层含义的含蓄态度并不意味着他们对此感到困惑。
以下单独的“后记”使此讨论与功能和命令式编程有关。
引用透明性,在函数式编程中通常使用的一个术语,意味着给定一个函数和一个输入值,您将始终收到相同的输出。也就是说,函数中没有使用外部状态。
这是引用透明函数的示例:
int plusOne(int x)
{
return x+1;
}
使用参照透明函数(给定输入和函数),您可以将其替换为值,而不用调用函数。因此,不用用参数5调用plusOne,我们可以将其替换为6。
另一个很好的例子是数学。在给定函数和输入值的数学中,它将始终映射到相同的输出值。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;
}
另一个示例是面向对象编程语言中的成员函数。成员函数通常对其成员变量进行操作,因此将是引用不透明的。成员函数当然可以是参照透明的。
另一个示例是从文本文件读取并打印输出的函数。该外部文本文件可以随时更改,因此该功能将是不透明的。
参照透明功能是仅依赖于其输入的功能。
[这是我3月25日以来的回答的后记,以使讨论更接近功能/命令式编程的关注。]
函数式程序员的引用透明性思想似乎与标准概念在以下三个方面有所不同:
哲学家/逻辑学家使用诸如“引用”,“表示”,“ designatum”和“ bedeutung ”(弗雷格的德语术语)之类的术语,而功能程序员则使用“值”一词。(这不完全是他们的工作。我注意到,Landin,Strachey及其后代也使用“值”一词来谈论参考/表示。这可能只是Landin和Strachey引入的术语简化,但似乎使天真地使用时有很大的差异。)
函数式程序员似乎相信这些“值”存在于编程语言中,而不是外部。在此过程中,他们既不同于哲学家,也不同于编程语言语义学家。
他们似乎认为这些“值”应该通过评估获得。
例如,维基百科上有关参照透明性的文章说,今天早上:
如果可以在不更改程序行为的情况下将其替换为其值(换句话说,产生具有相同效果并在相同输入上输出的程序),则该表达式被称为参照透明的。
这与哲学家/逻辑学家所说的完全不同。他们说,一个上下文是参考或引用透明如果在该上下文中的表达可通过另一替换表达式引用同样的事情(一个共指表达)。这些哲学家/逻辑学家是谁?它们包括Frege,Russell,Whitehead,Carnap,Quine,Church还有无数其他人 他们每个人都是高大的人物。至少可以说,这些逻辑学家的综合才智令人震惊。他们都是一致的立场,即语言只能说说内正式语言和表达外存在所指/ denotations 约他们。因此,该语言所能做的就是将一个表达式替换为引用同一实体的另一个表达式。语言中不存在引用对象/代名词。为什么函数式编程人员会偏离这种公认的传统?
人们可能会认为编程语言语义学家可能误导了他们。但是,他们没有。
兰丁:
(a)每个表达式都有一个嵌套子表达式结构,(b)每个子表达式都 表示某种东西(通常是数字,真值或数值函数),(c)表达式表示的东西,即其“值”,仅取决于它的子表达式的值,而不是它们的其他属性。[增加重点]
斯托伊:
表达式唯一重要的是它的值,任何子表达式都可以用任何其他相等的值代替[增加重点]。而且,表达式的值在一定范围内在出现时是相同的。”
表达式的值仅取决于其组成表达式的值(如果有),并且这些子表达式可以自由地由具有相同值的其他表达式替换[增加重点]。
因此,回想起来,Landin和Strachey通过用“值”替换“参考” /“符号”来简化术语的努力可能是有害的。一旦听到“价值”,就会想起一个导致它的评估过程。同样很容易想到将评估产生的任何内容都视为“值”,即使可能已经很清楚地知道这并非其含义。在函数式程序员看来,这就是我碰到的“参照透明”概念。但是,早期语义学家所说的“价值” 不是功能或任何类似事物的评估或输出的结果。这是该术语的含义。
一旦我们将表达的所谓“价值”(古典哲学家话语中的“指称”或“指称”)理解为一个复杂的数学/概念性对象,就会出现各种可能性。
函数式程序员不愿将此类语言称为“相对透明”,仅表示他们不愿将此类复杂的数学/概念对象视为“值”。另一方面,当状态转换程序使用自己喜欢的语法并用诸如“ monad”之类的时髦词修饰时,他们似乎非常愿意将状态转换程序称为“值”。我必须说,他们完全不一致,即使我们同意他们的“参照透明性”观念具有一定的连贯性。
一段历史可能会揭示这些混乱是如何产生的。对于克里斯托弗·斯特拉奇(Christopher Strachey)而言,1962年至1967年是一个非常密集的时期。1962-65年间,他在Maurice Wilkes担任兼职研究助理,以设计和实现后来被称为CPL的编程语言。这是一种命令式编程语言,但也具有强大的功能性编程语言功能。Landin是Strachey在其咨询公司的雇员,他对Strachey的编程语言观点产生了巨大的影响。在1965年具有里程碑意义的论文“ 下一种700种编程语言 ”中,Landin毫不掩饰地推广了函数式编程语言(称其为表示性语言)语言),并将命令式编程语言描述为它们的“对立面”。在随后的讨论中,我们发现Strachey质疑Landin的强势地位。
... DL构成所有语言的子集。它们是一个有趣的子集,但是除非您习惯了,否则使用起来很不方便。我们需要它们,因为目前我们还不知道如何使用包括命令和跳转在内的语言构造证明。[增加重点]
1965年,斯特拉奇(Strachey)担任牛津大学(Oxford)的读者一职,似乎基本上全职致力于发展命令式和跳跃式理论。到1967年,他已经准备好了一种理论,并在哥本哈根的一所夏季学校的“ 编程语言的基本概念 ”课程中教授了这一理论。这些讲义原本应该已经出版了,但是“不幸的是,由于进行了漫长的编辑,会议记录从未得以实现;然而,就像Strachey在牛津大学所做的许多工作一样,该论文也具有影响力。” (马丁·坎贝尔·凯利)
很难获得Strachey的著作,这可能会导致混乱的传播,人们不得不依赖次要来源和传闻。但是,既然“ 基本概念 ”已经可以在网络上找到,那么就无需诉诸猜测了。我们应该阅读它,并对Strachey的含义下定决心。特别是:
从根本上讲,在不理解L值,R值和其他构成命令式程序员概念范围的复杂对象之间的区别的情况下,谈论“参照透明性”是错误的。
对于那些需要简要说明的人,我将予以警告(但请阅读以下披露内容)。
编程语言中的参照透明性促进了方程式推理-参照透明性越多,进行方程式推理就越容易。例如,(伪)函数定义,
fx = x + x,
在此定义的范围内,可以轻松(安全地)用foo + foo替换f(foo),而对执行此还原的位置没有太多限制,这很好地表明了编程语言的引用透明性已。
例如,如果foo在C编程意义上是x ++,那么您将无法安全地执行此还原操作(也就是说,如果要执行此还原操作,您将不会得到与开始时相同的程序)。
在实际的编程语言中,您不会看到完美的引用透明性,但是函数式程序员比大多数人更关心它(请参阅Haskell,它是核心目标)。
(完全公开:我是一名函数程序员,因此,最重要的答案是您应该对这种解释有所保留。)
如果您对词源学感兴趣(即,为什么这个概念使用这个特殊名称),请查看我关于该主题的博客文章。该术语来自哲学家/逻辑学家奎因。
在[1]中,两种语言都有明确的含义:
2,由于对象和金属语言的接近性,它们可能会混淆。
作为语言实施者,我发现我需要不断记住这一区别。
因此,雷迪教授,我可以这样解释:-)
在功能编程和语义的上下文中,术语“ 参照透明性”不是参照透明的。
我希望以下答案可以补充并限定有争议的第一和第三答案。
让我们同意一个表达式表示或指代某个引用对象。但是,一个问题是,这些引用对象是否可以作为表达式本身的一部分进行同构编码,从而将此类表达式称为“值”。例如,文字数字值是算术表达式集的子集,真值是布尔表达式集的子集,依此类推。其想法是将表达式评估为其值(如果有一个值)。因此,“值”一词可以指代表达式集中的一个符号或一个可区分的元素。但是,如果引用对象和值之间存在同构(双射),则可以说它们是同一件事。(这就是说,必须谨慎定义引用对象和同构,这已经由指称语义学领域证明。data Nat = Zero | Suc Nat
不符合预期的自然数集。)
让我们来写E[·]
一个带有洞的表达式,在某些情况下也被称为“上下文”。类C表达式的两个上下文示例是[·]+1
和
[·]++
。
让我们[[·]]
为在某个提供含义的世界中编写一个带有表达式(不带孔)并传递其含义(引用,表示等)的函数编写。(我从指称语义学领域借用了表示法。)
让我们在某种程度上正式地修改Quine的定义,如下所示:E[·]
如果给定了两个表达式E1
并且E2
(那里没有孔),则上下文是参照透明的,[[E1]] = [[E2]]
即(表达式表示/引用相同的引用对象)则是这样的情况[[E[E1]]] = [[E[E2]]]
(即填充-在孔中使用或E1
或,E2
结果也表示相同的参照物)。
莱布尼兹用“等于”代替“等于”的规则通常表示为“ if
E1 = E2
then E[E1] = E[E2]
”,即E[·]
函数。一个功能(或为此功能计算程序的功能)是从源到目标的映射,因此每个源元素最多有一个目标元素。非确定性函数是错误的名词,它们要么是关系,要么是函数传递集合,等等。如果按照莱布尼兹的规则,相等性=
是指称的,那么双括号就被认为是理所当然的而被忽略了。因此,参照透明上下文是一个函数。莱布尼兹的规则是等式推理的主要组成部分,因此等式推理肯定与参照透明性相关。
尽管[[·]]
它是从表达式到符号的函数,但它可以是从表达式到“值”的函数,[[·]]
可以将其理解为表达式的受限子集,也可以理解为评估。
现在,if E1
是一个表达式,并且E2
是一个值,在定义表达式,值和评估的参照透明性时,我认为大多数人都具有这个意思。但是,如本页第一和第三答案所示,这是一个不准确的定义。
诸如此类的上下文问题[·]++
并不是副作用,而是C的值没有按照其含义同构地定义。函数不是值(嗯,指向函数的指针是),而在函数式编程语言中则是。Landin,Strachey和指称语义学的先驱在使用功能世界提供含义方面非常聪明。
对于类似C的命令式语言,我们可以使用函数大致为表达式提供语义[[·]] : Expression -> (State -> State x Value)
。
Value
是的子集Expression
。State
包含对(标识符,值)。语义函数采用表达式并将其含义从当前状态传递到具有更新状态和值的对。例如,[[x]]
是从当前状态到一对的函数,其第一部分为当前状态,第二部分为x的值。相反,[[x++]]
是从当前状态到该对的函数,其第一分量是x的值递增的状态,而第二分量就是该值。从这个意义上讲,如果上下文[·]++
满足上面给出的定义,则上下文是参照透明的。
我认为函数式程序员有权使用引用透明性,因为它们可以自然地[[·]]
作为函数从表达式恢复为值。函数是一等值,状态也可以是值,而不是符号。状态monad(部分地)是一种用于传递(或线程化)状态的干净机制。
我发现“ 计算机程序的结构和实现 ”(“向导程序 ”)一书中的引用透明的定义很有用,因为通过引入赋值操作来解释如何违反引用透明的说明对它进行了补充。请查看以下有关该主题的幻灯片:https : //www.slideshare.net/pjschwarz/introducing-assignment-invalidates-the-substitution-model-of-evaluation-and-violates-referential-transparency-as-在向导书中解释