让我以举例的方式介绍这个问题。这是从Martin Odersky的功能编程课程的第2.3讲中获得的。
我有一个函数来迭代地找到固定点
namespace WebApplication1.App_Code
{
public class CalBmiStd : BmiCalculator
{
}
}
我可以调整这个函数来找到像这样的平方根
object fixed_points {
println("Welcome to Fixed Points")
val tolerance = 0.0001
def isCloseEnough(x: Double, y: Double) =
abs((x-y)/x) < tolerance
def fixedPoint(f: Double => Double)(firstGuess: Double) = {
def iterate(guess: Double): Double = {
println(guess)
val next = f(guess)
if (isCloseEnough(guess, next)) next
else iterate(next)
}
iterate(firstGuess)
}
但是,对于某些参数(例如4),这并不会收敛。所以我对它应用平均阻尼,基本上将其转换为Newton-Raphson,如此
def sqrt(x: Double) =
fixedPoint(y => x/y)(1.0)
收敛。
现在平均阻尼足以保证其自身的功能,所以我重构我的代码
def sqrt(x: Double) =
fixedPoint(y => (x/y+y)/2)(1.0)
和
def averageDamp(f: Double => Double)(x: Double) = (x+f(x))/2
哇!刚刚发生了什么??我只使用 def sqrtDamp(x: Double) =
fixedPoint(averageDamp(y=>x/y))(1.0) (*)
只有一个参数(当它被定义为两个时),并且编译器没有抱怨!
现在,我知道我可以使用像这样的部分应用程序
averageDamp
没有问题。但当我尝试使用 def a = averageDamp(x=>2*x)_
a(3) // returns 4.5
少于必要数量的参数时(如averageDamp
中所做的那样),如此
sqrtDamp
我收到错误 def a = averageDamp(x=>2*x) (**)
。
问题:
答案 0 :(得分:1)
这个答案扩展了@ som-snytt发布的评论。
(**)和(*)之间的区别在于前者fixedPoint
提供了类型定义,而后者a
则没有。本质上,每当您的代码提供显式类型声明时,编译器都很高兴忽略了尾随下划线的遗漏。这是一个深思熟虑的设计决定,参见Martin Odersky的explanation。
为了说明这一点,这是一个小例子。
object A {
def add(a: Int)(b:Int): Int = a + b
val x: Int => Int = add(5) // compiles fine
val y = add(5) // produces the following compiler error
}
/* missing arguments for method add in object A;
follow this method with `_' if you want to treat it as a partially applied function
val y = add(5)
^
*/