【发布时间】:2014-12-03 22:00:29
【问题描述】:
我正在学习优秀的 Martin Odersky 的 FP 课程的讲座,其中一堂讲座通过牛顿寻找某些函数的不动点的方法演示了高阶函数。讲座中有一个关键步骤,我认为类型签名被违反了,所以我会要求解释。 (对于入站的冗长介绍表示歉意 - 它觉得它是必要的。)
这样一种算法的实现方式如下:
val tolerance = 0.0001
def isCloseEnough(x: Double, y: Double) = abs((x - y) / x) / x < tolerance
def fixedPoint(f: Double => Double)(firstGuess: Double) = {
def iterate(guess: Double): Double = {
val next = f(guess)
if (isCloseEnough(guess, next)) next
else iterate(next)
}
iterate(firstGuess)
}
接下来,我们尝试通过 fixedPoint 函数计算平方根,但天真的尝试通过
def sqrt(x: Double) = fixedPoint(y => x / y)(1)
被挫败,因为这种方法会摇摆不定(因此,对于sqrt(2),结果将在 1.0 和 2.0 之间无限交替)。
为了解决这个问题,我们引入了平均阻尼,因此基本上我们计算两个最接近的计算值的平均值并收敛到解,因此
def sqrt(x: Double) = fixedPoint(y => (y + x / y) / 2)(1)
最后,我们介绍averageDamp函数,任务是写sqrt与fixedPoint和averageDamp。 averageDamp 定义如下:
def averageDamp(f: Double => Double)(x: Double) = (x + f(x)) / 2
我不明白的部分来了——我最初的解决方案是这样的:
def sqrt(x: Double) = fixedPoint(z => averageDamp(y => x / y)(z))(1)
但是教授。 Odersky 的解决方案更简洁:
def sqrt(x: Double) = fixedPoint(averageDamp(y => x / y))(1)
我的问题是 - 为什么它有效?根据函数签名,fixedPoint 函数应该接受一个函数 (Double => Double) 但它不介意传递一个普通的 Double (这是 averageDamp 返回的 - 事实上,如果你尝试显式指定Double的返回类型为averageDamp,编译器不会报错)。
我认为我的方法正确地遵循了类型 - 那么我在这里缺少什么?在哪里指定或暗示(?)averageDamp 返回一个函数,特别是考虑到右侧显然返回一个标量?如何将标量传递给明确只需要函数的函数?您如何推断似乎不支持类型签名的代码?
【问题讨论】:
标签: scala functional-programming higher-order-functions