Scala 中的函数参数评估(函数式编程)

Function parameters evaluation in Scala (functional programming)

请在下面找到一段来自 Coursera 在线课程(讲座 2.3)的关于 Scala 函数式编程的代码。

package week2
import math.abs

object lecture2_3_next {
  def fixedPoint(f: Double => Double)(firstGuess: Double): Double = {
    val tolerance = 0.0001
    def isCloseEnough(x: Double, y: Double): Boolean = abs((x - y) / x) / x < tolerance
    def iterate(guess: Double): Double = {
      val next = f(guess)
      if (isCloseEnough(guess, next)) next
      else iterate(next)
    }
    iterate(firstGuess)
  }                                              

  def averageDamp(f: Double => Double)(x: Double): Double = (x + f(x)) / 2

  def sqrt(x: Double): Double = fixedPoint(averageDamp(y => x / y))(1)

  sqrt(2)                                         

} 

在我试图理解这段代码时有几点阻碍了我。

我希望你能帮助我理解这段代码。

让我恼火的2点是: - 当您调用 averageDamp 时,传递的函数中有 2 个参数 'x' 和 'y'(例如 averageDamp(y => x / y)),但您从未在定义中指定 'y' 参数averageDamp 函数(例如 def averageDamp(f: Double => Double)(x: Double): Double = (x + f(x)) / 2)。 Scala 编译器在哪里以及如何评估 'y' 参数。 - 第二点可能与第一点有关,其实我不知道。当我调用 averageDamp 函数时,我只传递函数 'f' 参数(例如 y => x / y),但我没有传递函数的第二个参数 'x'(例如 (x: Double)第二个参数)。在这种情况下,scala 编译器如何评估 'x' 参数以呈现 averageDamp 调用的结果。

我想我错过了一些关于 scala 和函数式编程的评估或替代模型的内容。

感谢您的帮助,新年快乐!

埃尔韦

1) 您没有将 xy 参数作为 f 传递,而是传递了一个函数。该函数定义为 y => x / y,其中 y 只是此函数参数的占位符,而 x 在此上下文中是固定值,因为它作为参数给出sqrt 方法(在示例中 x 是 2)。除了花哨的 lambda 语法,你也可以这样写

def sqrt(x: Double): Double = fixedPoint(averageDamp(
    new Function1[Double,Double] {
       def apply(y:Double):Double = x / y
    }
))(1)

这没什么神奇的,只是一个缩写。

2) 当你有第二个参数列表,并且在调用方法时不使用它,你做一些叫做 "currying" 的事情,你会得到一个部分函数。考虑

def add(x:Int)(y:Int) = x + y

如果你调用它为add(2)(3),一切都是"normal",你得到5。但是如果你调用add(2),第二个参数仍然是"missing" ,你会得到一个函数,它期待这个缺失的第二个参数,所以你有类似 y => 2 + y

的东西

x 不是(匿名)函数的参数,它是函数 sqrt 的参数。对于匿名函数,它是一个绑定闭包。

为了让它更明显,让我们重写它并使用命名函数而不是匿名函数:

def sqrt(x: Double): Double = fixedPoint(averageDamp(y => x / y))(1)

可以改写为:

def sqrt(x: Double): Double = {
   def funcForSqrt(y: Double) : Double = x / y  // Note that x is not a parameter of funcForSqrt

   // Use the function fundForSqrt as a parameter of averageDamp
   fixedPoint(averageDamp(funcForSqrt))(1) 
}