按值调用和按名称调用等价

Call-by-value and by-name equivalence

我正在参加 Coursera 的函数式编程课程,有时他们会讨论按值调用和按名称调用评估技术之间的区别。他们是让我感到困惑的一点,他们说:

Both techniques reduce to the same final values as long as:

  1. the reduced expressions consists of pure functions and
  2. both evaluations terminate

这似乎是一个 lambda 微积分定理。

你能解释一下 "the reduced expressions conssist of pure functions" 是什么意思吗?

纯函数是没有副作用的函数(例如执行 IO 或更改函数以外的任何值)。纯函数的一个例子是:

def inc(x: Int) = x+1

一个不纯函数的例子是:

var sum = 1
def addToSum(x: Int) = {
    sum += x
    sum
}

那么现在让我们考虑以下两种方法,它们的区别仅在于它们是按名称还是按值来获取参数:

def doubleByValue(x: Int) = x + x
def doubleByName(x: =>Int) = x + x

现在如果我们将这两个都与纯函数一起使用,结果是一样的:

doubleByValue(inc(2)) // => 6
doubleByName(inc(2)) // => 6

但是如果我们将它们应用到不纯函数中,结果会有所不同:

sum = 1 // Let's reset sum, so the result isn't affected by previous uses
doubleByValue(addToSum(2)) // => 6, the value of `sum` is now 3
sum = 1 // Let's reset sum, so the result isn't affected by previous uses
doubleByName(addToSum(2)) // => 8, the value of `sum` is now 5

区别在于ByName版本调用函数两次并将两次结果相加,而ByValue版本调用一次,保存结果并将其添加到自身。

对于纯函数,这完全没有区别 - 给定相同的参数,它总是 return 相同的结果,所以无论你调用它一次并使用保存的结果两次还是你调用它两次(性能除外)。

对于不纯的函数,它有很大的不同,因为每次调用函数时 sum 变量的值都会改变。