我对可变类的“引用透明度”的理解是否正确?

时间:2014-11-20 05:59:20

标签: scala functional-programming referential-transparency

从scala"中的函数编程一书中,我看到"参考透明"的定义。表达式:

  

如果对于所有程序p,p中所有出现的e都可以被评估e的结果替换而不影响p的含义,则表达式e是引用透明的。

我有一些代码示例,我不确定它们是否具有引用透明性。

我将在可变类

的示例中使用scala.collection.mutable.StringBuilder

1

val x = new StringBuilder("Hello")

println(x.length)
println(x.length)

假设此处的代码是使用x的完整代码。

我可以说表达式x是一个参照透明表达式吗?

如果我更改所有x及其值new StringBuilder("Hello"),则程序的可观察行为不会更改:

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")

假设此处的代码是使用xy的完整代码。

我可以说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的含义是什么,它是否意味着现有的完整代码?或者可能添加的任何可能的代码?

2 个答案:

答案 0 :(得分:2)

这意味着您可能编写包含该表达式的任何可能的程序p。恰当地,这应该根据语言或一组可能的程序来定义。因此,您的x在语言中是引用透明的,其中唯一有效的程序是您编写的。您的y在Scala子集中是引用透明的,您不允许在.append 上调用StringBuilder。但这些并不是特别有趣的语言。

大多数时候,当人们谈论&#34;引用透明&#34;表达式,它们(隐含地)意味着像Scalazzi safe subset of Scala这样的东西,它足以表达(所有?)有用的Scala程序,但足够安全,可以推理。因为当然,如果你被允许打电话,例如System.identityHashCode(),大多数据称是&#34;参考透明&#34;表达式实际上不是。

当然,最重要的定义是可操作的定义;什么是&#34;参考透明&#34;最终取决于你想用它做什么。一个重要的用例是编译器/库优化:我们不希望编译器执行您在示例1中给出的替换,因为对于大多数程序来说这&#34;优化&#34;会改变程序的含义。但是我们很高兴编译器通过内联不可变常量来优化我们的程序,因为我们的程序&#34;不应该&#34;#34;取决于特定常数的identityHashCode是什么。

答案 1 :(得分:1)

据我所知,表达&#39; e&#39;在引用方面是透明的,它是否适用于所有可能的程序&#39; p&#39;。

它可以是&#34;参考透明的&#34;对于具体的节目&#39; p&#39;,但如果你可以写另一个节目&#39; px&#39;这将违反&#34;替换规则&#34;,这意味着表达不是参照透明的。

  import scala.collection.mutable

  val b = new mutable.StringBuilder("Hello")
  def e = b.length

  def p0 = {
    val l1 = e
    val l2 = e
    l1 + l2
  }

  def p1 = {
    val l1 = e
    b.append("World")
    val l2 = e
    l1 + l2
  }

可以建立程序&#39; p&#39;这将违反&#34; e中的e可以用e&#34; - 这意味着&#39; e&#39;不是指称透明的。在可变状态下,构建此程序非常容易。

在p0中我们可以说e是参考透明的,但是p1很容易打破它。