这些术语的定义似乎确实不同,但我一直认为其中一个暗示着另一个。我无法想到表达式是引用透明但不纯粹的任何情况,反之亦然。
维基百科为这些概念维护着单独的文章,并表示:
来自引用透明度:
如果涉及到的所有函数
表达式是纯函数,那么
该表达式是参考的
透明的。还有一些不纯的
函数可以包含在
表达式,如果它们的值为
被丢弃,它们的副作用是
微不足道。
来自纯表达式:
需要纯函数
构造纯表达式。 [...] 纯的
表达式通常被称为
参照透明。
我觉得这些说法令人困惑。如果所谓的“不纯函数”的副作用微不足道足以允许不执行它们(即用其值替换对此类函数的调用)而无需实质上改变程序,就好像它本来就是纯粹的一样,不是吗?
是否有一种更简单的方法来理解纯表达式和引用透明表达式之间的差异(如果有)?如果存在差异,我们将不胜感激,提供一个清楚地表明差异的示例表达式。
The terms do appear to be defined differently, but I've always thought of one implying the other; I can't think of any case when an expression is referentially transparent but not pure, or vice-versa.
Wikipedia maintains separate articles for these concepts and says:
From Referential transparency:
If all functions involved in the
expression are pure functions, then
the expression is referentially
transparent. Also, some impure
functions can be included in the
expression if their values are
discarded and their side effects are
insignificant.
From Pure expressions:
Pure functions are required to
construct pure expressions. [...] Pure
expressions are often referred to as
being referentially transparent.
I find these statements confusing. If the side effects from a so-called "impure function" are insignificant enough to allow not performing them (i.e. replace a call to such a function with its value) without materially changing the program, it's the same as if it were pure in the first place, isn't it?
Is there a simpler way to understand the differences between a pure expression and a referentially transparent one, if any? If there is a difference, an example expression that clearly demonstrates it would be appreciated.
发布评论
评论(8)
如果我把我认识的任何三位理论家聚集在一个地方,他们中至少有两位不同意“参照透明度”一词的含义。当我还是个年轻的学生时,我的一位导师给了我一篇论文,解释说即使你只考虑专业文献,“参照透明”一词也至少用来表示三种不同的含义。 (不幸的是,那篇论文在一箱重印本中,尚未扫描。我在 Google Scholar 中搜索了它,但没有成功。)
我无法通知您,但我可以建议您提供上:因为即使是一小群尖刻的语言理论家也无法就其含义达成一致,所以“参照透明”这个术语没有用。所以不要使用它。
PS 对于任何与编程语言语义有关的主题,维基百科都是不可靠的。我已经放弃尝试修复它了;维基百科的流程似乎更重视变化和民众投票而不是稳定性和准确性。
If I gather in one place any three theorists of my acquaintance, at least two of them disagree on the meaning of the term "referential transparency." And when I was a young student, a mentor of mine gave me a paper explaining that even if you consider only the professional literature, the phrase "referentially transparent" is used to mean at least three different things. (Unfortunately that paper is somewhere in a box of reprints that have yet to be scanned. I searched Google Scholar for it but I had no success.)
I cannot inform you, but I can advise you to give up: Because even the tiny cadre of pointy-headed language theorists can't agree on what it means, the term "referentially transparent" is not useful. So don't use it.
P.S. On any topic to do with the semantics of programming languages, Wikipedia is unreliable. I have given up trying to fix it; the Wikipedian process seems to regard change and popular voting over stability and accuracy.
所有纯函数都必然是引用透明的。由于根据定义,它们无法访问除传递的内容之外的任何内容,因此它们的结果必须完全由它们的参数确定。
然而,有可能具有非纯的引用透明函数。我可以编写一个函数,给定一个 int
i
,然后生成一个随机数r
,从自身中减去r
并将其放入>s
,然后返回i - s
。显然这个函数是不纯的,因为它生成随机数。然而,它是参照透明的。在这种情况下,这个例子是愚蠢且做作的。然而,在 Haskell 中,id
函数的类型为a ->; a
而我的stupidId
函数的类型为a ->; IO a
表明它利用了副作用。当程序员可以通过外部证明保证他们的函数实际上是引用透明的时,他们可以使用unsafePerformIO
将IO
从类型中剥离出来。All pure functions are necessarily referentially transparent. Since, by definition, they cannot access anything other than what they are passed, their result must be fully determined by their arguments.
However, it is possible to have referentially transparent functions which are not pure. I can write a function which is given an int
i
, then generates a random numberr
, subtractsr
from itself and places it ins
, then returnsi - s
. Clearly this function is impure, because it is generating random numbers. However, it is referentially transparent. In this case, the example is silly and contrived. However, in, e.g., Haskell, theid
function is of typea - > a
whereas mystupidId
function would be of typea -> IO a
indicating that it makes use of side effects. When a programmer can guarantee through means of an external proof that their function is actually referentially transparent, then they can useunsafePerformIO
to strip theIO
back away from the type.我有点不确定我在这里给出的答案,但肯定有人会给我们指出某个方向。 :-)
“纯度”通常被认为意味着“没有副作用”。如果一个表达式的求值没有副作用,则称该表达式是纯表达式。那有什么副作用呢?在纯函数式语言中,副作用是任何不遵循简单 beta 规则的东西(评估函数应用的规则与用实际参数替换所有自由出现的形式参数相同)。
例如,在具有线性(或唯一性,这种区别目前不应该打扰)类型的函数语言中,允许某些(受控)突变。
所以我想我们已经弄清楚了“纯度”和“副作用”可能是什么。
引用透明度(根据您引用的维基百科文章)意味着变量可以用它表示的表达式(缩写,代表)替换,而不改变手头程序的含义(顺便说一句,这也是一个很难解决的问题,并且我不会在这里尝试这样做)。因此,“纯度”和“引用透明度”确实是不同的东西:“纯度”是某些表达式的属性,大致意味着“执行时不会产生副作用”,而“引用透明度”是与变量和表达式相关的属性它代表并意味着“变量可以用它所表示的内容替换”。
希望这有帮助。
I'm somewhat unsure of the answer I give here, but surely somebody will point us in some direction. :-)
"Purity" is generally considered to mean "lack of side-effects". An expression is said to be pure if its evaluation lacks side-effects. What's a side-effect then? In a purely functional language, side-effect is anything that doesn't go by the simple beta-rule (the rule that to evaluate function application is the same as to substitute actual parameter for all free occurrences of the formal parameter).
For example, in a functional language with linear (or uniqueness, this distinction shouldn't bother at this moment) types some (controlled) mutation is allowed.
So I guess we have sorted out what "purity" and "side-effects" might be.
Referential transparency (according to the Wikipedia article you cited) means that variable can be replaced by the expression it denotes (abbreviates, stands for) without changing the meaning of the program at hand (btw, this is also a hard question to tackle, and I won't attempt to do so here). So, "purity" and "referential transparency" are indeed different things: "purity" is a property of some expression roughly means "doesn't produce side-effects when executed" whereas "referential transparency" is a property relating variable and expression that it stands for and means "variable can be replaced with what it denotes".
Hopefully this helps.
纯函数是指每次调用都返回相同值的函数,并且没有副作用。
引用透明度意味着您可以用绑定变量的值替换它,并且仍然收到相同的输出。
既是纯的又是引用透明的:
为什么是纯的?
因为它是仅输入
x
的函数并且没有副作用。为什么这是引用透明的?
您可以将
f1
中的t1
和t2
替换为它们在return
语句,如下所示,在每种情况下,
f2
仍将始终返回与f1
相同的结果。纯粹,但不是引用透明:
让我们修改
f1
如下:让我们通过替换
t1
和t2< 再次尝试相同的技巧/code> 及其右侧,看看它是否是
f3
的等效定义。我们可以很容易地观察到,
f3
和f4
在用其右侧/值替换变量方面并不等效。f3(1)
将返回9
,f4(1)
将返回36
。引用透明,但不纯粹:
只需修改
f1
以接收x
的非本地值,如下所示:执行相同的替换练习before 表明
f5
仍然是引用透明的。然而,它不是纯粹的,因为它不仅仅是传递给它的参数的函数。仔细观察,我们从
f3
到f4
失去引用透明度的原因是x
被修改了。在一般情况下,创建一个变量final
(或者熟悉Scala的人,使用val
s而不是var
s)并使用不可变对象可以帮助保持函数的引用透明。这使得它们更像是代数或数学意义上的变量,从而更适合形式验证。Pure functions are those that return the same value on every call, and do not have side effects.
Referential transparency means that you can replace a bound variable with its value and still receive the same output.
Both pure and referentially transparent:
Why is this pure?
Because it is a function of only the input
x
and has no side-effects.Why is this referentially transparent?
You could replace
t1
andt2
inf1
with their respective right hand sides in thereturn
statement, as followsand
f2
will still always return the same result asf1
in every case.Pure, but not referentially transparent:
Let's modify
f1
as follows:Let us try the same trick again by replacing
t1
andt2
with their right hand sides, and see if it is an equivalent definition off3
.We can easily observe that
f3
andf4
are not equivalent on replacing variables with their right hand sides / values.f3(1)
would return9
andf4(1)
would return36
.Referentially transparent, but not pure:
Simply modifying
f1
to receive a non-local value ofx
, as follows:Performing the same replacement exercise from before shows that
f5
is still referentially transparent. However, it is not pure because it is not a function of only the arguments passed to it.Observing carefully, the reason we lose referential transparency moving from
f3
tof4
is thatx
is modified. In the general case, making a variablefinal
(or those familiar with Scala, usingval
s instead ofvar
s) and using immutable objects can help keep a function referentially transparent. This makes them more like variables in the algebraic or mathematical sense, thus lending themselves better to formal verification....以及引用透明度的定义:
来自页面176 of 使用 Miranda 进行函数式编程 作者:Ian霍利尔:
<块引用>
8.1 价值观和行为
纯函数式语言的语义最重要的属性是该语言的声明性视图和操作性视图完全一致,如下所示:
<表类=“s-表”>
<标题>
每个表达式都表示一个值,并且有一些值
对应于所有可能的程序行为。
任何上下文中表达式产生的行为
完全由其值决定,反之亦然。
这一原则通常被不透明地称为引用透明度,也可以用以下方式表示:
以及来自 函数式编程语言中具有引用透明度的非确定性作者:F. Warren Burton:
<块引用>
[...] 表达式在同一环境中始终具有相同值的属性 [...]
...有关各种其他定义,请参阅 引用透明度、确定性和可折叠性 作者:Harald Søndergaard 和 Peter Sestoft。
相反,我们将从“纯度”的概念开始。对于你们三个还不知道的人来说,你们正在阅读本文的计算机或设备是一台固态图灵机,一种与效果本质上相关的计算模型。因此,每个程序,无论是功能性程序还是其他程序,都需要使用这些效果来完成任务TM。
这对于纯度意味着什么?在汇编语言级别,即 CPU 的领域,所有程序都是不纯粹的。如果您正在用汇编语言编写程序,那么您就是对所有这些效果之间的相互作用进行微观管理的人 - 这真的很乏味!
大多数时候,您只是在指导CPU 在计算机内存中移动数据,这只会更改各个内存位置的内容 - 那里什么也看不到!只有当您的指令指示 CPU 写入视频内存时,您才会观察到可见的变化(屏幕上出现的文本)。
出于我们的目的,我们将效果分为两个粗略类别:
在这种情况下,纯度仅意味着不存在那些可观察到的影响,这些影响会导致正在运行的程序(甚至可能是其主机)的环境发生明显的变化。绝对不是所有效果都没有,否则我们就得更换固态图灵机了!
现在,对于
42生命、宇宙和一切的问题,术语“参照透明度”到底意味着什么 - 而不是放牧猫试图让理论家们达成一致,让我们尝试找到这个术语的原始含义。对我们来说幸运的是,这个术语经常出现在 Haskell 的 I/O 上下文中 - 我们只需要一篇相关文章...这里有一篇:摘自 Owen Stephen 的 函数式 I/O 方法:遵循参考文献:
来自 Christopher Strachey 的 编程语言中的基本概念中的第 9 页(共 39 页) :
<块引用>
表达式最有用的属性之一是 Quine 引用透明性所调用的属性。本质上,这意味着如果我们希望找到包含子表达式的表达式的值,关于子表达式我们唯一需要知道的就是它的值。子表达式的任何其他特征,例如其内部结构、其组件的数量和性质、它们的求值顺序或写入它们的墨水颜色,都与主表达式的值无关。表达。
摘自 Willard Van Ormond Quine 的第 163 页(共 314 页)单词和对象:
<块引用>
[...] 引用因此中断了术语的指称力,可以说是指称透明度失败2。 [...]我称限制模式 Φ 是指称透明的,如果每当出现单数术语 t 时,在术语或句子中纯粹是指称 ψ(t),它在包含术语或句子 Φ(ψ(t)) 中也纯粹是指称。
带有脚注:
<块引用>
2 该术语来自 Whitehead 和 Russell,第 2 版,第 1 卷。 1,p。 665.
根据该参考文献:
来自 数学原理,作者:阿尔弗雷德·诺斯·怀特海 (Alfred North Whitehead) 和伯特兰·罗素 (Bertrand Russell):
<块引用>
当一个断言发生时,它是通过一个特定的事实来做出的,该事实是所断言的命题的一个实例。但这个特殊的事实可以说是“透明的”;没有人谈论它,只是通过它谈论了一些别的东西。这是出现在真值函数中的命题的“透明”品质。
让我们尝试将所有这些结合在一起:
因此,这是奎因的原始定义或斯特雷奇的改编定义之间的选择。如果您愿意,您可以尝试自己翻译奎因的定义 - 每个曾经对“纯功能”的定义提出异议的人甚至可能会喜欢有机会争论一些不同的问题,例如“遏制模式” em>”和“纯粹参考”实际上意味着...玩得开心!我们其他人只会接受 Strachey 的定义有点模糊(“在本质 [...]”)并继续:
(由我强调。)
关于该描述(“如果我们希望找到 [...] 的值”),一个类似但更简洁的声明是Peter Landin 在 未来 700 种编程语言中给出:
因此:
Strachey 提供了一些示例:
(第 12 页,共 39 页)
<块引用>
我们倾向于自动假设表达式中的符号 x,例如 3x2 + 2x + 17 代表每次出现相同的事情(或具有相同的值)。这是引用透明度最重要的结果,只有凭借这个属性,我们才能使用上一节中描述的 where 子句或 λ 表达式。
(第 16 页)
<块引用>
当使用(或调用或应用)函数时,我们编写f[ε],其中ε可以是表达式。如果我们使用引用透明的语言,为了计算 f[ε] ,我们需要了解表达式 ε 就是它的值。
因此,根据 Strachey 的原始定义,引用透明度意味着纯度 - 在没有评估顺序的情况下,可观察到的效果和其他效果是 实际上没用...
...along with definitions of referential transparency:
from page 176 of Functional programming with Miranda by Ian Holyer:
and from Nondeterminism with Referential Transparency in Functional Programming Languages by F. Warren Burton:
...for various other definitions, see Referential Transparency, Definiteness and Unfoldability by Harald Søndergaard and Peter Sestoft.
Instead, we'll begin with the concept of "purity". For the three of you who didn't know it already, the computer or device you're reading this on is a solid-state Turing machine, a model of computing intrinsically connected with effects. So every program, functional or otherwise, needs to use those effects To Get Things DoneTM.
What does this mean for purity? At the assembly-language level, which is the domain of the CPU, all programs are impure. If you're writing a program in assembly language, you're the one who is micro-managing the interplay between all those effects - and it's really tedious!
Most of the time, you're just instructing the CPU to move data around in the computer's memory, which only changes the contents of individual memory locations - nothing to see there! It's only when your instructions direct the CPU to e.g. write to video memory, that you observe a visible change (text appearing on the screen).
For our purposes here, we'll split effects into two coarse categories:
In this situation, purity just means the absence of those observable effects, the ones which cause a visible change to the environment of the running program, maybe even its host computer. It is definitely not the absence of all effects, otherwise we would have to replace our solid-state Turing machines!
Now for the question of
42life, the Universe and everythingwhat exactly is meant by the term "referential transparency" - instead ofherding catstrying to bring theorists into agreement, let's just try to find the original meaning given to the term. Fortunately for us, the term frequently appears in the context of I/O in Haskell - we only need a relevant article...here's one: from the first page of Owen Stephen's Approaches to Functional I/O:Following the references:
From page 9 of 39 in Christopher Strachey's Fundamental Concepts in Programming Languages:
From page 163 of 314 in Willard Van Ormond Quine's Word and Object:
with the footnote:
Following that reference:
From page 709 of 719 in Principa Mathematica by Alfred North Whitehead and Bertrand Russell:
Let's try to bring all that together:
So it's a choice between Quine's original or Strachey's adapted definition. You can try translating Quine's definition for yourself if you like - everyone who's ever contested the definition of "purely functional" might even enjoy the chance to debate something different like what "mode of containment" and "purely referential" really means...have fun! The rest of us will just accept that Strachey's definition is a little vague ("In essence [...]") and continue on:
(emphasis by me.)
Regarding that description ("that if we wish to find the value of [...]"), a similar, but more concise statement is given by Peter Landin in The Next 700 Programming Languages:
Thus:
Strachey provides some examples:
(page 12 of 39)
(and on page 16)
So referential transparency, by Strachey's original definition, implies purity - in the absence of an order of evaluation, observable and other effects are practically useless...
这些来自 ACCU2015 演讲的幻灯片关于引用透明度主题的精彩总结。
来自其中一张幻灯片:
例如,您可以拥有一个将其计算记录到程序标准输出的函数(因此,它不会是纯函数),但您可以用不记录其计算的类似函数替换对此函数的调用。因此,该函数具有引用透明性。但是......正如幻灯片所强调的那样,上面的定义是关于语言,而不是表达。
从我们的定义来看,不,不是。
尝试我上面提到的幻灯片。
These slides from one ACCU2015 talk have a great summary on the topic of referential transparency.
From one of the slides:
You can have, for instance, a function that logs its computation to the program standard output (so, it won't be a pure function), but you can replace calls for this function by a similar function that doesn't log its computation. Therefore, this function have the referential transparency property. But... the above definition is about languages, not expressions, as the slides emphasize.
From the definitions we have, no, it is not.
Try the slides I mentioned above.
我将引用 John Mitchell 编程语言中的概念 。他定义纯函数式语言必须通过声明性语言测试,即无副作用或无副作用。
在语言学中,如果名称或名词短语可以被具有相同指称的另一个名词短语替换而不改变其所包含的句子的含义,则该名称或名词短语被认为是指称透明的。
在第一种情况下是成立的,但在第二种情况下它就变得太奇怪了。
如果 Walter 拥有 Centro 那么我们可以将给定句子中的替换为:
与第一个相反:
鲁弗斯的意思是有点红色,指的是英格兰的威廉四世。
“由于他的胡子,他被称为威廉四世”。看起来太别扭了。
传统的说法是,如果我们可以在程序中的任何位置将一个表达式替换为另一个具有相同值的表达式而不改变程序的含义,那么一种语言就是引用透明的。
因此,引用透明性是纯函数式语言的一个属性。
如果你的程序没有副作用,那么这个属性将成立。
因此,放弃它是一个很棒的建议,但在这种情况下,坚持下去也可能看起来不错。
I'll quote John Mitchell Concept in programming language. He defines pure functional language has to pass declarative language test which is free from side-effects or lack of side effects.
In linguistics a name or noun phrase is considered referentially transparent if it may be replaced with the another noun phrase with same referent without changing the meaning of the sentence it contains.
Which in 1st case holds but in 2nd case it gets too weird.
And if Walter own a Centro then we could replace that in the given sentence as:
Contrary to first :
Rufus means somewhat red and reference was to William IV of England.
"He was called William IV because of his read beard." looks too awkward.
Traditional way to say is, a language is referentially transparent if we may replace one expression with another of equal value anywhere in the program without changing the meaning of the program.
So, referential transparency is a property of pure functional language.
And if your program is free from side effects then this property will hold.
So give it up is awesome advice but get it on might also look good in this context.
考虑这个 javascript 示例,术语“纯函数”意味着有一个函数,通过在任何位置调用它多少次,始终可以为相同的输出生成相同的输入。
术语“引用透明性”意味着有一个纯函数,并且可以通过在运行时或编译时调用它来在某些地方替换其输出。
因此,纯函数的引用透明是一个始终可以为相同输出生成相同输入的函数,可以通过在运行时或编译时调用它来在某些地方进行替换。
因此,在此示例中,add 和 plus 函数也是纯函数且引用透明。
Consider this javascript example, the term pure function means there has a function that can always be produced the same input for same output by invoking it at every where and how many times.
The term referential transparency means there has a pure function and its output can be replaced at some where by invoking it at run-time or compile-time.
So, the referentially transparent of a pure function is a function that can always be produced the same input for same output can be replaced at some where by invoking it at run-time or compile-time.
So, in this example, both the add and plus functions are also pure and referentially transparent.