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

时间:2015-11-25 00:51:12

标签: scala functional-programming currying partial-application

让我以举例的方式介绍这个问题。这是从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) (**)

问题:

  1. 我在(**)中所做的与(*)不同的是,编译器在前者而不是后者中抱怨?
  2. 所以看起来在某些情况下允许使用少于必需参数。这些情况是什么?这个机制的名称是什么? (我意识到这将属于“currying&#39;”的主题,但我在这个currying子集的具体名称之后,就像它一样)

1 个答案:

答案 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)
              ^
*/