【问题标题】:Is my understanding of "referential transparency" with mutable classes correct?我对可变类的“引用透明度”的理解是否正确?
【发布时间】:2014-11-20 05:59:19
【问题描述】:

从《scala中的函数式编程》一书中,我看到了一个表达式的“引用透明”的定义:

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

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

我将在示例中使用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是什么意思,是指现有的完整代码吗?或者任何可能添加的代码?

【问题讨论】:

    标签: scala functional-programming referential-transparency


    【解决方案1】:

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

    大多数时候,当人们谈论“引用透明”的表达式时,他们(隐含地)指的是 Scalazzi safe subset of Scala 之类的东西,这对于表达(所有?)有用的 Scala 程序来说足够通用,但是足够安全,可以推理。因为当然,如果你被允许打电话,例如System.identityHashCode(),大多数据称“引用透明”的表达式实际上并非如此。

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

    【讨论】:

      【解决方案2】:

      据我了解,表达式“e”是引用透明的,它是否对所有可能的程序“p”都是引用透明的。

      对于具体程序“p”可以是“类引用透明”,但如果你可以编写另一个违反“替换规则”的程序“px”,则表示表达式不是引用透明的。

        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
        }
      

      有可能构建程序 'p' 会违反“p 中的 e 可以被评估 e 的结果替换”——这意味着 'e' 不是引用透明的。使用可变状态,构建这个程序非常容易。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-05
        • 2018-04-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-29
        • 1970-01-01
        • 2011-12-07
        相关资源
        最近更新 更多