具有多个参数列表的函数可以(有时)使用少于所需数量的参数的机制是什么?

What is the mechanism by which functions with multiple parameter lists can (sometimes) be used with less than the required number of parameters?

这个问题我举个例子介绍一下。这摘自 Martin Odersky 的函数式编程课程的第 2.3 讲。

我有一个函数可以像这样迭代地找到不动点

 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)
  }

我可以像这样调整这个函数来求平方根

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

但是,对于某些参数(例如 4),这并不收敛。所以我对其应用平均阻尼,基本上将其转换为 Newton-Raphson,就像这样

  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)                (**)

我收到一个错误 missing arguments for method averageDamp

问题:

  1. 我在 (**) 中所做的与编译器在前者中抱怨但在后者中没有抱怨的 (*) 有何不同?
  2. 所以看起来在某些情况下使用少于必要的参数是允许的。这些情况是什么?这种机制的名称是什么? (我知道这会属于 'currying' 的主题,但我在追寻这个柯里化子集的具体名称,就像它一样)

此答案扩展了@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)
              ^
*/