3

从“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用它的 value改变 all 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")

假设这里的代码是使用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意思,是指现有的完整代码吗?或者任何可能添加的代码?

4

2 回答 2

2

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

大多数时候,当人们谈论“引用透明”表达式时,他们(隐含地)指的是 Scala 的 Scalazzi 安全子集之类的东西,它足够通用,可以表达(所有?)有用的 Scala 程序,但安全足以推理。因为当然,如果您被允许调用 eg System.identityHashCode(),大多数据称“引用透明”的表达式实际上不是。

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

于 2014-11-20T08:30:16.263 回答
1

据我了解,表达式'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 很容易破坏它。

于 2014-11-20T06:28:14.797 回答