开发者

What is the point of multiple parameter clauses in function definitions in Scala?

I'm trying to understand the point of this language feature of multiple parameter clauses and why you would use it. Eg, what's the difference between these two functions really?

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' 

There's something on this in the Scala specificati开发者_高级运维on at point 4.6. See if that makes any sense to you.

NB: the spec calls these 'parameter clauses', but I think some people may also call them 'parameter lists'.


Here are three practical uses of multiple parameter lists,

  1. To aid type inference. This is especially useful when using higher order methods. Below, the type parameter A of g2 is inferred from the first parameter x, so the function arguments in the second parameter f can be elided,

    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. For implicit parameters. Only the last parameter list can be marked implicit, and a single parameter list cannot mix implicit and non-implicit parameters. The definition of g3 below requires two parameter lists,

    // analogous to a context bound: g3[A : Ordering](x: A)
    def g3[A](x: A)(implicit ev: Ordering[A]) {}
    
  3. To set default values based on previous parameters,

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


TwoParamClause involves two method invocations while the OneParamClause invokes the function method only once. I think the term you are looking for is currying. Among the many use cases, it helps you to breakdown the computation into small steps. This answer may convince you of usefulness of currying.


There is a difference between both versions concerning type inference. Consider

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

Here, the type A is bound to Any, which is a super type of String and Int. But:

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

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

As you see, the type checker only considers the first argument list, so A gets bound to String, so the Int value for aa in the second argument list is a type error.


Multiple parameter lists can help scala type inference for more details see: Making the most of Scala's (extremely limited) type inference

Type information does not flow from left to right within an argument list, only from left to right across argument lists. So, even though Scala knows the types of the first two arguments ... that information does not flow to our anonymous function.

...

Now that our binary function is in a separate argument list, any type information from the previous argument lists is used to fill in the types for our function ... therefore we don't need to annotate our lambda's parameters.


There are some cases where this distinction matters:

  1. Multiple parameter lists allow you to have things like TwoParamClauses(2); which is automatically-generated function of type Int => Int which adds 2 to its argument. Of course you can define the same thing yourself using OneParamClause as well, but it will take more keystrokes

  2. If you have a function with implicit parameters which also has explicit parameters, implicit parameters must be all in their own parameter clause (this may seem as an arbitrary restriction but is actually quite sensible)

Other than that, I think, the difference is stylistic.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜