阅读"Scala中的函数式编程",我对异常部分不具有引用透明性感到有些困惑。
给出的例子是
def failingFn(i: Int): Int = {
val y: Int = throw new Exception("fail!")
try {
val x = 42 + 5
x + y
}
catch { case e: Exception => 43 }
}
因此,书中给出的论点是y
在引用上是不透明的,因为如果我们将其代入try
块中的主体中,我们会得到与直接运行函数不同的结果。这对我来说没有任何意义,因为整个函数一开始都是非终止的,所以说函数体内的值在引用上不透明有什么意义呢?我心中的天真替换如下
def failingFn(i: Int): Int = {
val y: Int = throw new Exception("fail!")
try {
val x = 42 + 5
x + ((throw new Exception("fail!")): Int)
}
catch { case e: Exception => 43 }
}
并且仍然失败,但出现相同的异常。
此外,y
本身是一个非值(它不能直接评估为一个值),那么谈论此类表达式的引用透明度有什么意义呢?我怀疑这里有某种花招,所以我的推理到底在哪里不正确?
书中的观点是,如果它真的是引用透明的,那么你可以完全删除y
变量并在try/catch
中替换它,你最终会得到不同的语义。
因此,要指出的是,在例外的情况下,对例外的评估点很重要。
也许你可以争辩说这两个程序在语义上并不相同,因为评估的位置才是这里真正重要的。如果你做了y
lazy
,那么结果不会改变。