0

让我通过一个例子来介绍这个问题。这是从马丁·奥德斯基的函数式编程课程的讲义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个)。所以我对它应用平均阻尼,基本上将它转换成牛顿 - 拉夫森像

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. 因此,在某些情况下,允许使用少于必需的参数。这些情况是什么,这个机制的名称是什么? (我意识到这将在'咖喱'的主题下,但我是在这个柯里子集的具体名称,因为它)
+3

'fixedPoint'接受一个函数,所以它愿意扩展你的arg。另一种用法没有预期的类型,所以它不会。这是一个常见问题。 –

回答

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) 
      ^
*/ 
相关问题