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) 您没有将 x
和 y
参数作为 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)
}
请在下面找到一段来自 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) 您没有将 x
和 y
参数作为 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)
}