引用透明性在计算机科学中,引用透明性和引用不透明性是部分计算机程序具有的属性。若一个表达式在被其相应的值替换时能不改变程序的行为(反之亦然),则该表达式是引用透明的。 [1]因此,该表达式必须是纯函数——给予相同的输入,其返回值必须相同;对其求值时不能含有副作用。反之,一个不具有应用透明性的表达式是引用不透明的。 在数学中,根据构成数学函数的定义,所有函数应用都是引用透明的。然而,在编程中情况并非总是如此;为避免歧义,函数经常被归类为过程或方法。函数式编程的一个定义特征是它只允许引用透明的函数。一些其他编程语言有提供方法用以选择地保证引用透明性。一些函数式编程语言要求所有函数必须引用透明。 引用透明性的重要性在于允许程序员和编译器将程序行为作为重写逻辑进行推理。这有助于证明正确性、简化算法、在不破坏代码的情况下协助修改代码,以及通过记忆、公共子表达式消除、惰性求值或并行计算来优化代码。 历史应用透明性的概念据称起源于阿尔弗雷德·诺斯·怀特海和伯特兰·罗素的《数学原理》(1910–1913年)。 [2]它被威拉德·范·奥曼·蒯因引入分析哲学。在《词与物》(1960年)第30章中,蒯因给出了如下定义:
该术语出现在其当代计算机科学用法中,在编程语言中对变量的讨论中,在Christopher Strachey的开创性讲义集《编程语言中的基本概念》(1967 年)中。讲义引用了蒯因的《词与物》。 例子和反例如果表达式中涉及的所有函数都是纯函数,则该表达式是引用透明的。 假设有函数可以从某个来源接受输入并将其返回。在伪代码中,该函数可能以 一个更为微妙的例子是使函数可以具有自由变量,即某些未被明确作为参数传递的输入;然后根据名称绑定规则将其解析为非局部变量,例如全局变量、当前执行环境中的变量(用于动态绑定)或闭包中的变量(用于静态绑定)。由于可以在不更改作为参数传递的原值的情况下更改此变量,因此即便参数相同,后续调用该函数的结果也可能不同。然而,在纯函数式编程中,破坏性赋值是不允许的,因此如果自由变量被静态绑定到一个值,该函数仍是引用透明的,因为非局部变量及其值都分别由于静态绑定和不可变性而不可改变。 算术运算是引用透明的: 重新赋值是不透明的。例如,C语言表达式
在无副作用的语言,例如Haskell中,可以“用等于代替等于”:若 与命令式编程对比如果用其值替换表达式仅在程序执行的某个时刻有效,则该表达式不是引用透明的。这些序列点的定义和排序是命令式编程的理论基础,也是命令式编程语言语义的一部分。 然而,因为引用透明的表达式可以在任何时候求值,所以不需要定义序列点,也不需要任何求值顺序的保证。不考虑这些因素而完成的编程称为纯函数式编程。 以引用透明的方式编写代码的一个优点是静态代码分析对一个智能编译器会更容易,并且可以自动进行更好的代码改进转换。例如,在使用 C 语言编程时,如果在循环内包含对昂贵函数的调用,则会导致性能下降,即使可以在不更改程序结果的情况下将函数调用移出循环。程序员此时将被迫执行调用的手动代码移动,但这可能会以牺牲源代码的可读性为代价。但是,如果编译器能够确定函数调用是引用透明的,它可以自动执行此转换。 强制引用透明性的语言的主要缺点是它们使自然适合步骤序列命令式编程风格的操作的表达更加笨拙和不够简洁。这些语言通常包含使这些任务更容易的机制,同时保留语言的纯功能质量,例如定字句语法和单子。 又例
有两个函数,一个是引用透明的( int g = 0;
int rt(int x) {
return x + 1;
}
int ro(int x) {
g++;
return x + g;
}
函数 int i = ro(x) + ro(y) * (ro(x) - ro(x));
人们可能会想将这一陈述简化为: int i = ro(x) + ro(y) * 0;
int i = ro(x) + 0;
int i = ro(x);
然而这并不正确,因为
但是,可以使用更复杂的分析来将语句简化为: int tmp = g; int i = x + tmp + 1 + (y + tmp + 2) * (x + tmp + 3 - (x + tmp + 4)); g = g + 4;
int tmp = g; int i = x + tmp + 1 + (y + tmp + 2) * (x + tmp + 3 - x - tmp - 4)); g = g + 4;
int tmp = g; int i = x + tmp + 1 + (y + tmp + 2) * (-1); g = g + 4;
int tmp = g; int i = x + tmp + 1 - y - tmp - 2; g = g + 4;
int i = x - y - 1; g = g + 4;
这需要更多步骤,并且要求程序员对编译器优化不可行的代码有一定程度的洞察力。 因此,引用透明性使程式設計者能够推理其代码,这将导致更健壮的程序,找到不希望通过测试找到的错误的可能性,以及看到优化机会的可能性。 另见参考
外部链接 |
Portal di Ensiklopedia Dunia