Scala中函数定义中的多个参数子句有什么意义?

时间:2011-09-02 04:44:23

标签: scala functional-programming currying

我试图理解多个参数子句的这种语言特征以及为什么要使用它。 例如,这两个函数之间的区别是什么?

class WTF {
    def TwoParamClauses(x : Int)(y: Int) = x + y
    def OneParamClause(x: Int, y : Int) = x + y
}

>> val underTest = new WTF
>> underTest.TwoParamClauses(1)(1) // result is '2'
>> underTest.OneParamClause(1,1) // result is '2' 

Scala specification at point 4.6中有一些内容。看看这对你有意义。

注意:规范称这些'参数子句',但我认为有些人也可能称之为'参数列表'。

5 个答案:

答案 0 :(得分:9)

以下是多个参数列表的三种实际用法,

  1. 帮助进行类型推断。这在使用高阶方法时特别有用。下面,A的类型参数g2是从第一个参数x中推断出来的,因此第二个参数f中的函数参数可以省略,

    def g1[A](x: A, f: A => A) = f(x)
    g1(2, x => x) // error: missing parameter type for argument x
    
    def g2[A](x: A)(f: A => A) = f(x)
    g2(2) {x => x} // type is inferred; also, a nice syntax
    
  2. 对于隐式参数。只有最后一个参数列表可以隐式标记,并且单个参数列表不能混合隐式和非隐式参数。下面g3的定义需要两个参数列表,

    // analogous to a context bound: g3[A : Ordering](x: A)
    def g3[A](x: A)(implicit ev: Ordering[A]) {}
    
  3. 根据以前的参数设置默认值

    def g4(x: Int, y: Int = 2*x) {} // error: not found value x
    def g5(x: Int)(y: Int = 2*x) {} // OK
    

答案 1 :(得分:8)

TwoParamClause涉及两个方法调用,而OneParamClause只调用 function 方法一次。我认为你要找的术语是 currying 。在众多用例中,它可以帮助您将计算细分为小步骤。这answer可能会让你相信currying的用处。

答案 2 :(得分:6)

两个版本之间在类型推断方面存在差异。考虑

def f[A](a:A, aa:A) = null
f("x",1)
//Null = null

此处,A类型绑定到Any,这是StringInt的超级类型。但是:

def g[A](a:A)(aa:A) = null
g("x")(1)

error: type mismatch;
 found   : Int(1)
 required: java.lang.String
       g("x")(1)
              ^

如您所见,类型检查器仅考虑第一个参数列表,因此A绑定到String,因此第二个参数中Int的{​​{1}}值list是类型错误。

答案 3 :(得分:4)

多个参数列表可以帮助进行scala类型推断以获取更多详细信息,请参阅:Making the most of Scala's (extremely limited) type inference

  
    

类型信息不会从左到右参数列表中,只能从从左到右参数列表< / strong>即可。所以,即使Scala知道前两个参数的类型......信息也不会流向我们的匿名函数。

         

...

         

现在我们的二元函数在一个单独的参数列表中,来自之前参数列表的任何类型信息都用于填写我们函数的类型 ...因此我们不需要注释我们的lambda参数。

  

答案 4 :(得分:3)

在某些情况下,这种区别很重要:

  1. 多个参数列表允许您使用TwoParamClauses(2);这是类型Int =&gt;的自动生成函数。 Int为其参数增加了2。当然你也可以使用OneParamClause自己定义相同的东西,但它需要更多的击键

  2. 如果你有一个隐式参数的函数也有显式参数,隐式参数必须全部在他们自己的参数子句中(这可能看起来像一个任意的限制,但实际上是非常明智的)

  3. 除此之外,我认为,不同之处在于风格。