这些术语确实以不同的方式定义 ,但我总是想到一个暗示另一个;当表达式是引用透明但不纯粹时,我无法想到任何情况,反之亦然。
维基百科为这些概念维护单独的文章并说:
如果涉及的所有功能 那么表达式就是纯函数 表达是指称的 透明。还有一些不纯的 功能可以包含在 表达式,如果它们的值是 丢弃和他们的副作用 微不足道的。
需要纯粹的功能 构建纯粹的表达。 [...]纯净 表达式通常被称为 被引用透明。
我发现这些陈述令人困惑。如果来自所谓的“不纯函数”的副作用无关紧要足以允许不执行它们(即用其值替换对这样一个函数的调用)改变程序,就像它首先是纯粹的一样,不是吗?
有没有更简单的方法来理解纯表达式和引用透明表达式之间的差异(如果有的话)?如果存在差异,则可以理解清楚地表明它的示例表达。
答案 0 :(得分:39)
如果我在一个地方聚集了我认识的三位理论家,其中至少有两位不同意“参照透明度”一词的含义。当我还是一名年轻学生时,我的导师给了我一篇论文,解释说即使你只考虑专业文献,“引用透明”这个短语也用来表示至少三种不同的东西。 (不幸的是,这篇论文是在一盒尚未被扫描的重印版中的某个地方。我搜索了Google学术搜索,但我没有成功。)
我无法通知你,但我可以建议你放弃:因为即使是那些尖头语言理论家的小干部也不能就它的意思达成一致,“引用透明”一词无效。所以不要使用它。
P.S。关于与编程语言的语义有关的任何主题,维基百科都是不可靠的。我放弃了试图解决它;维基百科过程似乎关注稳定性和准确性的变化和普遍投票。
答案 1 :(得分:7)
所有纯函数都必须是引用透明的。因为根据定义,他们无法访问除了传递内容之外的任何内容,因此他们的结果必须完全由他们的论据决定。
但是,可以使用不是纯粹的引用透明函数。我可以编写一个赋予int i
的函数,然后生成一个随机数r
,从自身中减去r
并将其放在s
中,然后返回{{1} }}。很明显,这个功能是不纯的,因为它产生随机数。但是,它是参考透明的。在这种情况下,这个例子很愚蠢和做作。但是,在例如Haskell中,i - s
函数的类型为id
,而我的a - > a
函数的类型为stupidId
,表示它使用了副作用。当程序员可以通过外部证明保证他们的功能实际上是引用透明的时候,那么他们可以使用a -> IO a
将unsafePerformIO
从该类型中剥离出去。
答案 2 :(得分:4)
我有点不确定我在这里给出的答案,但肯定会有人指出我们在某个方向。 : - )
“纯度”通常被认为是指“缺乏副作用”。如果一个表达的评价没有副作用,那么它就是纯粹的表达。什么是副作用呢?在纯函数式语言中,副作用是任何不符合简单beta规则的东西(评估函数应用程序的规则与替换形式参数的所有自由出现的实际参数相同)。
例如,在具有线性(或唯一性,这种区别不应该在此刻打扰)的函数式语言中,允许使用某种(受控制的)突变类型。
所以我想我们已经找出了“纯度”和“副作用”的含义。
引用透明度(根据您引用的维基百科文章)意味着变量可以被表示的表达式(缩写,代表)替换,而不会改变手头程序的含义(顺便说一句,这也是一个难题解决,我不会尝试这样做)。因此,“纯度”和“参照透明度”确实是不同的东西:“纯度”是某种表达的属性,粗略地表示“在执行时不产生副作用”,而“参照透明度”是与变量和表达相关的属性。它代表并意味着“变量可以用它所代表的东西代替”。
希望这有帮助。
答案 3 :(得分:1)
These slides from one ACCU2015 talk对参考透明度主题有一个很好的总结。
从其中一张幻灯片中:
例如,你可以使用一个将计算记录到程序标准输出的函数(因此,它不是一个纯函数),但是你可以通过一个类似的函数替换对这个函数的调用。记录它的计算。因此,此函数具有引用透明度属性。但是......上面的定义是关于语言,而不是表达,正如幻灯片所强调的那样。如果(a),语言是引用透明的 每个子表达式都可以被任何其他子表达式替换 这等于它的价值和(b)所有出现的 给定上下文中的表达式产生 相同的价值。
[...]就像它首先是纯净的一样,不是吗?
从我们的定义来看,不,它不是。
是否有更简单的方法来理解纯表达式和引用透明表达式之间的差异(如果有的话)?
答案 4 :(得分:-1)
我将引用约翰米切尔在他的书 Concept in programming language中所写的内容。我不会逐行记住它,但他定义纯函数式语言必须通过声明性语言测试,即:
"在x1,...,xn的特定减速范围内,所有出现的仅包含变量x1,...,xn的表达式e具有相同的值。"
总之,其他人都提到没有副作用或没有副作用("缺乏"副作用)。
在语言学中,如果名称或名词短语可以被替换为具有相同指称词的另一个名词短语而不改变其包含的句子的含义,则该词组被认为是引用透明的。
在第一种情况下,但在第二种情况下它变得太奇怪了。
案例1: "我看到沃尔特进入他的新汽车。"
如果沃尔特拥有一个Centro,那么我们可以在给定的句子中替换为:
"我看到沃尔特进入他的 Centro "
与第一个相反:
案例#2:由于他的胡子,他被称为 William Rufus 。
Rufus意味着有点红,参考英格兰的威廉四世。
"他被称为威廉四世,因为他读了胡子。"看起来太尴尬了。
传统的说法是,如果我们可以在程序中的任何地方将一个表达式替换为另一个具有相同值的表达式而不改变程序的含义,则该语言是引用透明的。
因此,引用透明度是纯函数式语言的属性。 如果您的程序没有副作用,那么此属性将保留。
所以放弃它是很棒的建议,但是在这种情况下,它可能看起来也很好。