gpt4 book ai didi

scala - scala 是否忽略函数签名中的类型?

转载 作者:行者123 更新时间:2023-12-04 23:49:25 24 4
gpt4 key购买 nike

我正在学习优秀的 Martin Odersky 的 FP 类(class)的讲座,其中一堂讲座通过牛顿寻找某些函数的不动点的方法演示了高阶函数。讲座中有一个关键步骤,我认为类型签名被违反了,所以我会要求解释。 (对于入站的冗长介绍表示歉意 - 它觉得它是必要的。)

实现这种算法的一种方法如下:

  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函数和任务是写 sqrtfixedPointaverageDamp . 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 function 应该接受一个函数( Double => Double ),但它不介意传递一个普通的 Double (这是 averageDamp 返回的内容 - 实际上,如果您尝试将 Double 的返回类型显式指定为 averageDamp ,编译器不会抛出错误)。

我认为我的方法正确地遵循了类型 - 那么我在这里缺少什么? averageDamp 在哪里指定或暗示(?)返回一个函数,特别是考虑到右侧显然返回一个标量?如何将标量传递给明确只需要函数的函数?您如何推断似乎不尊重类型签名的代码?

最佳答案

您的解决方案是正确的,但它可以更简洁。

让我们仔细检查averageDamp功能更紧密。

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

添加了返回类型注释以使其更清晰。我认为您缺少的是:

but it doesn't mind being passed an ordinary Double (which is what averageDamp returns - in fact, if you try to explicitly specify the return type of Double to averageDamp, the compiler won't throw an error).



但是 averageDamp(y => y/x)确实返回 Double => Double功能! averageDamp需要通过 两个 返回 Double 的参数列表.

如果函数只接收一个参数,它仍然希望完成另一个参数。因此,它不是立即返回结果,而是返回一个函数,说“我这里还需要一个参数,喂给我,这样我就会返回你想要的”。

莫教授确实通过了 一个 它的函数参数,不是两个,所以 averageDamp部分应用,在某种意义上它返回一个 Double => Double功能。

该类(class)还将告诉您具有多个参数列表的函数是这样的语法糖形式:
def f(arg1)(arg2)(arg3)...(argN-1)(argN) = (argN) => f(arg1)(arg2)(arg3)...(argN-1)

如果你给的参数比 f 需要的少,它只会返回等式的右边,即一个函数。所以,请注意 averageDamp(y => x / y) , 传递给 fixPoint 的参数,实际上是一个功能应该可以帮助您理解问题。

注意:部分应用函数(或函数柯里化(Currying))和多参数列表函数之间存在一些区别

例如你不能这样声明
val a = averageDamp(y => y/2)

编译器会提示这一点,因为“方法不是部分应用的函数”。

此处解释了差异: What's the difference between multiple parameters lists and multiple parameters per list in Scala? .

关于scala - scala 是否忽略函数签名中的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26270514/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com