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,
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.
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
Related
I am trying to understand Partially applied function in scala
scala> val a=sum _
a: (Int, Int, Int) => Int = <function3>
scala> a(1,2,3)
res7: Int = 6
I am just giving this val a=sum _
I want to understand how scala interprets it will take 3 arguments
a: (Int, Int, Int) => Int = <function3>
You've just experienced the eta-expansion that is converting a method into a function.
Your method is sum which you are not demonstrating but based on the function version must be:
def sum(a:Int,b:Int,c:Int):Int = a + b + c
The underscore you are adding at the end is converting your method into a function as the descriptive type signature of the result shows: (Int, Int, Int) => Int
This way you are converting your method into a function value that can be assigned to a variable and passed around in your application logic conveying a behavioural change to your data (addition in your instance).
This is slightly different from this question.
I want to define a function type that have default value defined.
Like this:
trait Foo {
type MyFunction = (Int, Option[Int] = 0) => Boolean
def checkInts(f: MyFunction)
}
Is it possible? If yes, how can I achieve this? If not, why?
Read here why you can't have default arguments in anonymous functions and how to make something similar - In Scala, can you make an anonymous function have a default argument?
But if you just need a way to pass a function taking 2 or 1 argument, you can always use simpler approach:
trait Foo {
type MyFunc1 = (Int) => Boolean
type MyFunc2 = (Int, Int) => Boolean
def checkInts(f: MyFunc1)
def checkInts(f: MyFunc2)
// common code of checkInts could be in some private method
}
Based on my knowledge so far you cannot define a type with default parameters. A type is a type.
What you can do is define a partially applied function.
Taking as an example the following function:
scala> def factorOf(x: Int, y: Int) = y % x == 0
factorOf: (x: Int, y: Int)Boolean
If you want a shortcut to the function without retaining any parameters, you can use the wildcard operator (_) assignment
scala> val f = factorOf _
f: (Int, Int) => Boolean = <function2>
scala> val x = f(7, 20)
x: Boolean = false
If you want to retain some of the parameters, you can partially apply the function by using the wildcard operator to take the place of one of the parameters. The wildcard operator here requires an explicit type, because it is used to generate a function value with a declared input type:
scala> val multipleOf3 = factorOf(3, _: Int)
multipleOf3: Int => Boolean = <function1>
scala> val y = multipleOf3(78)
y: Boolean = true
The new function value, multipleOf3, is a partially applied function, because it contains some but not all of the parameters for the factorOf() function.
A cleaner way to partially apply functions is to use functions with multiple parameter lists. This is a technique
known as currying the function:
scala> def factorOf(x: Int)(y: Int) = y % x == 0
factorOf: (x: Int)(y: Int)Boolean
scala> val isEven = factorOf(2) _
isEven: Int => Boolean = <function1>
scala> val z = isEven(32)
z: Boolean = true
Given the
def sum(a: Int, b: Int) = a + b
val add7 = sum(7, _)
// compiler complains missing $x1's type for $x1 => sum(7, $x1)
val add8 = sum(8, _: Int)
// fine
And curried sum can do this without type declaration .
def sum_curry(a: Int)(b: Int) = a + b
val add9 = sum_curry(9)(_)
// fine
But it's not a generic function, what sum's parameter types can be known and it is already there.
Why cannot Scala know the $x1's type from b: Int in sum's signature?
The compiler needs to know the data types of function arguments to map a function call to exactly one function definition (out of many overloaded function definition of with same name)
It will become ambiguous if we try a reverse mapping from function definition to function call to determine the type of a parameter in function call.
Eta expression can convert this to a value type (Int, Int) => Int only when:
_ as in place of the argument of list
val f = sum _
or, you just omit the argument list.
val f :(Int, Int) => Int = sum
and specify its type.
or use each _
val f = sum(_ , _)
As you can see, sum(7, _) cannot satisfy any of above.
I'm trying to figure out the difference between def and var/val when declaring a function in Scala.
Say we have a function:
scala> def f(x: Int) = { x * 2 }
f: (x: Int)Int
And another function g:
scala> var g = (x:Int) => x*2
g: Int => Int = <function1>
Apparently they are the same in the following way:
scala> f(2)
res0: Int = 4
scala> g(2)
res1: Int = 4
However, I could do
g = f
g: Int => Int = <function1>
but not
scala> f = g
<console>:13: error: missing arguments for method f;
follow this method with `_' if you want to treat it as a partially applied function
val $ires6 = f
^
<console>:10: error: reassignment to val
f = g
^
Question 1: why does this happen? I'm guessing that def maps to val.
Question 2: if I use val instead of var in declare g, are they equivalent? If not, what is the difference then?
I then try:
scala> def three( timetwo:(Int) => Int ) = { timetwo(3) }
three: (timetwo: Int => Int)Int
scala> three(g)
res47: Int = 6
scala> three(f)
res48: Int = 6
Question 3: does it mean (x: Int)Int is the same as Int => Int = <function1>? If so, is there some situation that we should favor one over the other?
Things is getting wired with the _ (underscore),
scala> three(f _)
res49: Int = 6
scala> three(g _)
<console>:11: error: type mismatch;
found : () => Int => Int
required: Int => Int
three(g _)
^
Question 4: why does this happen? What's the usage of _(underline) in Scala?
why does this happen? I'm guessing that def maps to val.
def is a method (in JVM terms) so it doesn't make sense to assign it.
The parser is then confused and it ultimately tries to save the day by interpreting the assignment f = g as
val $ires6 = f
f = g
Both statements are illegal, so you get two errors:
you can't assign a method to a val without an explicit type annotation or a _ expansion - see below)
you can't reassign a val (in case you are wondering, $ires6 is a fresh val introduced by the REPL)
if I use val instead of var in declare g, are they equivalent? If not, what is the difference then?
The difference is that val cannot be reassigned (i.e. it's a constant reference), whereas var can (i.e. it's a mutable reference).
More on the subject here: What is the difference between a var and val definition in Scala?
does it mean (x: Int)Int is the same as Int => Int = ? If so, is there some situation that we should favor one over the other?
Methods and functions are not the same, although the compiler does its best to make you believe they are, through a transformation called eta-expansion. In some cases such transformation can be performed automatically, in some others you need to be explicit and trigger it with a trailing _.
In your specific example (passing a method where a function is expected) the expansion can been performed automatically.
You can read this Q/A for a more in-depth discussion about which style to prefer.
why does this happen? What's the usage of _(underline) in Scala?
The underscore (_) has many uses in scala, one of which is the one I mentioned before, i.e. triggering the eta expansion of a method into a function.
That's a special syntax for methods, so you simply can't apply it to a function, as it would make no sense.
That's why you can do f _ (which will turn the f method into a function), but you can't do g _ (since g it's already a function).
Suppose I have the following code:
val someNumbers = List(-11, -10, -5, 0, 5, 10)
someNumbers.foreach( println _ )
val j = 10
(x: Int) => x + j
My question is Are partially applied functions and Closures orthogonal in Scala? This presentation seems to suggest that they are.
EDIT: 13 July 2014 [Changed code above]
It's really easy to see what's being returned when you go into the repl:
scala> type IntPairPred = (Int, Int) => Boolean
defined type alias IntPairPred
scala> val gt: IntPairPred = _ > _
gt: IntPairPred = <function2>
scala> gt(2,3)
res3: Boolean = false
What gt is, is a function2 i.e. a function that takes 2 parameters
Here's another example:
scala> def fn(a: Int, b: Int) = () => a + b
fn: (a: Int, b: Int)() => Int
scala> val a = fn(2,3)
a: () => Int = <function0>
What fn returns, is a function0 i.e. a function that doesn't take any parameters
Sorry but your example doesn't seem to refer to partial application, at least to me.
You're just using some shortcut syntax to define regular functions.
Actually gt, ge, ... definitions are expanded to something pretty like
val gt: IntPairPred = (x: Int, y: Int) => x > y
val gt: IntPairPred = (x: Int, y: Int) => x >= y
//and so on...
Regular functions support modification of its arguments, but this is not what you're looking for, I presume.
To define a closure, you should define a partial function referring to a variable in the outer scope, like
var one = 1
val gt1 = gt(1, _: Int)
assert(gt1(0)) //ok
assert(!gt1(1)) //ok
one = 2 //weirdo!
assert(gt1(0)) //ok
assert(gt1(1)) //ok
assert(!gt1(2)) //ok
So the point is not in functions definition or partial application. The point is if, at definition time, you're using variables from the closing scope within your function. In this case your function is influenced by the variable you closed over.
Is this what you were after?