简体   繁体   中英

scala function literal and methods and underscore

I have a very simple piece of code that I am not able to get grasp of. I am reading function literals, and methods. I am doing this in repl.

scala> val v = (a:Int, b:Int, c:Int) => {a+b+c}
v: (Int, Int, Int) => Int = $$Lambda$1368/1731643198@4ae730ca

scala> val v1 = v(1,2,_:Int)
v1: Int => Int = $$Lambda$1369/903167315@93d6f4

scala> v1 (10)
res29: Int = 13

scala>

scala> val v2 = v _
v2: () => (Int, Int, Int) => Int = $$Lambda$1370/5485285@7dd5d17a

scala> val v3 = v2()
v3: (Int, Int, Int) => Int = $$Lambda$1368/1731643198@4ae730ca

scala> val v4 = v3(1,2,3)
v4: Int = 6

scala> def sumMe(a:Int, b:Int, c:Int) = { a+b+c}
sumMe: (a: Int, b: Int, c: Int)Int

scala> val v7 = sumMe _
v7: (Int, Int, Int) => Int = $$Lambda$1371/906350712@6c86938f

scala> v7(1,2,3)
res30: Int = 6

I need some help in understanding on what happens above. I will start from the bottom of the code. When I create the method sumMe and assign it to "v7" with "_" on the right, I know I am not executing the method. The output of val v7= sumMe_ is quite clear to me as it simply tells me that v7 will take 3 params, and return an int. It feels OK so far.

Now when I go to my `val v1 = v(1,2,_:Int), I can still correlate that it will create a function object and assign to v1 and in fact I am using Scala s Function1's apply method is what I view it as.

I am hoping I understand it right so far. If my understanding above is right, what causes the most confusion is val v2 = v _ . And based on the output of what I see I have to call this thing differently. Basically I am not able to understand why v2 is different from v7. v2 takes no arguments and gives me a function which I can call. If that is always the case with function literals of the kind that I have defined as val v = ... , then when I do val v1 = v(1,2,:_Int) why don't I get this from scala v1:()=>Int=>Int which is similar to v2's case .

And lastly, why won't v7=sumMe _ not give me the same output as val v2 = v_

In Scala, we differentiate methods from functions . When you define sumMe , you're defining a method, while your other declarations are functions. Methods, in Scala, are non value types , meaning the method itself has no value. When you try to assign it to a value, there is an implicit conversion called eta expansion that is done to convert it to the corresponding function type. From the specification:

Method types do not exist as types of values. If a method name is used as a value, its type is implicitly converted to a corresponding function type.

Now that we're equipped with the knowledge of methods and functions, lets analyze what happens.

When I create the method sumMe and assign it to "v7" with "_" on the right, I know I am not executing the method

That's right. When you do sumMe _ , you're using eta-expansion to convert the method to a function.

Now when I go to my val v1 = v(1, 2, _: Int) , I can still correlate that it will create a function object and assign to v1

Again, you're right. v1 is now a partially applied function of type Function1[Int, Int] .

Basically I am not able to understand why v2 is different from v7.

What is v2 ? It is a function object which was created by partially applying an existing function object. Since this function of type Function3[Int, Int, Int, Int] is already fixed in it's parameter list, partially applying it only nests it in another function object, now of type Function0 , making it a Function0[Function3[Int, Int, Int, Int]] .

In Scala, functions are value that means you can assign any function in a variable. Whenever you apply placeholder("_") in front of def it will convert def into function with same input and output types. If you apply placeholder in front of value it will convert into function that take unit as input and return value as output**[() => T]**. for example:

 scala> val a = 2
 a: Int = 2

scala> val fun1  = a _
fun1: () => Int = <function0>

scala> def sum(a:Int, b:Int) = a+ b
sum: (a: Int, b: Int)Int

scala> val fun2 = sum _
fun2: (Int, Int) => Int = <function2>

whenever you are trying to pass partial input parameters in a "def" it will return partial applied function. For example:

scala> val fun3 = sum(1,_:Int)
fun3: Int => Int = <function1>

fun3 is called partial applied function.

There are something need to clear for function and method ,

  1. function : we use val and var to define the function , it's often is an Anonymous Function , In Scala , there are Function0 , Function1 , Function2 ... for these Anonymous Function , and the function type like: (T0, T1...TN) => U .

    so function v actually is a Function3 with 3 parameters.

  2. method : it's used to def to declare with method body with the parameters and return type .

For val v2 = v _ actually equals to val v2 = () => v , in there wildcard _ will expand to () => v , and v2 means it's a function to create another function( v ) without parameter.So val v3 = v2() means invoke v2() to create v function, so essentially v3 equal to v .

For val v7 = sumMe _ this means convert method sumMe to a function, in there wildcard _ will expand to (a: Int, b: Int, c: Int) => sumMe(a, b, c) , so sumMe _ will create a new function that's essentially equal to v , if you use v7 _ it also will create the same function like val v2 = v _ .

Reference :

Difference between method and function in Scala

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM