从《Functional programming in scala》一书中看到表达式的“引用透明”的定义:
An expression e is referentially transparent if, for all programs p, all occurrences of e in p can be replaced by the result of evaluating e without affecting the meaning of p.
我有一些代码示例,我不确定它们是否是引用透明的。
我将在示例中使用 scala.collection.mutable.StringBuilder
,这是一个可变类
1.
val x = new StringBuilder("Hello")
println(x.length)
println(x.length)
假设这里的代码是使用x
的完整代码。
我可以说表达式 x
是引用透明表达式吗?
如果我用它的值 new StringBuilder("Hello")
更改所有 x
,程序的可观察行为不会改变:
val x = new StringBuilder("Hello")
println(new StringBuilder("Hello").length)
println(new StringBuilder("Hello").length)
2.
val x = new StringBuilder("Hello")
val y = x.append("aaa")
假设这里的代码是使用x
和y
的完整代码。
我能说 y
是引用透明的吗,因为它根本没有在程序中使用?
3.
def getTheClassName(n:Int):String = {
val x = new StringBuilder("hello")
for(int i=0;i<n;i++) {
x.append("world")
}
return x.getClass.getName
}
我可以说 x
是引用透明的吗?因为不管我怎么替换它的值,返回值都不会改变。
PS:可能主要问题是我不明白for all programs p
是什么意思,是指现有的完整代码吗?或者可以添加任何可能的代码?
最佳答案
这意味着对于任何可能的程序p
你可能会写包含那个表达。正确地,这应该针对一种语言或一组可能的程序来定义。所以你的 x
在唯一有效的程序是您编写的语言中,是引用透明的。你的y
在不允许调用 .append
的 Scala 子集中引用透明 在 StringBuilder
上。但这些都不是特别有趣的语言。
大多数时候,当人们谈论“引用透明”表达式时,他们(隐含地)指的是像 Scalazzi safe subset of Scala 这样的东西。 ,这足以表达(所有?)有用的 Scala 程序,但足够安全以进行推理。因为当然如果你被允许打电话System.identityHashCode()
,大多数所谓的“引用透明”表达式实际上不是。
当然,最重要的定义是操作定义;什么是“参照透明”最终取决于你想用它做什么。一个重要的用例是编译器/库优化:我们不希望编译器执行您在示例 1 中给出的替换,因为对于大多数程序而言,这种“优化”会改变程序的含义。但我们很高兴编译器通过内联不可变常量来优化我们的程序,因为我们的程序“不应该”依赖于 identityHashCode
的内容。一个特定的常数是。
关于scala - 我对带有可变类的 "referential transparency"的理解是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27032779/