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).
Related
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
This question already has an answer here:
Eta-expansion between methods and functions with overloaded methods in Scala
(1 answer)
Closed 7 years ago.
I can find a document specifying the Scala rule about coercion of functions passed to higher-order function (... the method decorator.layout is coerced automatically to a value of type Int => String).
If I defined the following.
object Foo {
def bar[T1, R](f: T1 => R): T1 => R = f
}
def fn1(s: String): Int = 1
Then in the REPL I can do:
scala> Foo.bar({ s: String => 1 })
res: String => Int = <function1>
scala> Foo.bar(fn1)
res: String => Int = <function1>
Everything is fine and clear up to there, but if I update Foo:
object Foo {
def bar[T1, R](f: T1 => R): T1 => R = f
// NEW
def bar[T1, T2, R](f: Function2[T1, T2, R]): Tuple2[T1, T2] => R = { case (c1, c2) => f(c1, c2) }
}
Then in the REPL:
scala> Foo.bar({ s: String => 1 })
res: String => Int = <function1>
scala> Foo.bar(fn1)
<console>:12: error: missing arguments for method fn1;
follow this method with `_' if you want to treat it as a partially applied function
Foo.bar(fn1)
Some this call bar(fn1) which was working with the first version of Foo need to be updated in the following way.
scala> Foo.bar(fn1 _)
res: String => Int = <function1>
That's fine but I would like to make sure which rules the Scala compiler follows about that, when the syntax higherFn(fn) can be used and when it cannot (and that syntax higherFn(fn _) is required).
I guess the polymorphism of the higher-order function has something to do with that...
Shortly saying, higherFn(fn1) can be used when compiler knows what type is expected from fn, like T1 => R in the first case. When overloading occurs compiler should choose appropriate method first, so the expected type is unknown at the time.
P.S. IMHO, compiler could be smarter here, but it seems to be more complex to implement/describe for now.
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?
Is there a syntax to allow generic type parameters on function literals? I know I could wrap it in a method such as:
def createLongStringFunction[T](): (T) => Boolean = {
(obj: T) => obj.toString.length > 7
}
but then I end up needing to invoke the method for every type T and getting a new function. I looked through the language reference, and while I see that the function literal syntax is translated by the compiler to an instance of a Functionn object that itself has generic input types, it looks like the compiler magic realizes those parameters at the time of creation. I haven't found any syntax that allows me to, in effect, "leave one or more of the type parameters of Functionn unbound". What I would prefer is something along the lines of:
// doesn't compile
val longStringFunction: [T](T) => Boolean = (obj: T) => obj.toString.length > 7
Does any such thing exist? Or for that matter, what is the explicit type of an eta-expansion function when the method being expanded has generic parameters?
This is a purely contrived and useless example. Of course I could just make the function use Any here.
No, type parameters only apply to methods and not function objects. For example,
def f[T](x: T) = x //> f: [T](x: T)T
val g = f _ //> g: Nothing => Nothing = <function1>
// g(2) // error
val h: Int=>Int = f _ //> h : Int => Int = <function2>
h(2) //> res0: Int = 2
The method f cannot be converted to a polymorphic function object g. As you can see, the inferred type of g is actually Function1[Nothing, Nothing], which is useless. However, with a type hint we can construct h: Function1[Int,Int] that works as expected for Int argument.
As you say, in your example all you're requiring is the toString method and so Any would be the usual solution. However, there is call for being able to use higher-rank types in situations such as applying a type constructor such as List to every element in a tuple.
As the other answers have mentioned, there's no direct support for this, but there's a relatively nice way to encode it:
trait ~>[A[_],B[_]] {
def apply[X](a : A[X]) : B[X]
}
type Id[A] = A //necessary hack
object newList extends (Id ~> List) {
def apply[X](a : Id[X]) = List(a)
}
def tupleize[A,B, F[_]](f : Id ~> F, a : A, b : B) = (f(a), f(b))
tupleize(newList, 1, "Hello") // (List(1), List(Hello))
Since longStringFunction defined as followed is a value, which must have some given type.
val longStringFunction: (T) => Boolean = (obj: T) => obj.toString.length > 7
However, you can reuse a function object with a method:
scala> val funObj: Any => Boolean = _.toString.size > 7
funObj: Any => Boolean = <function1>
scala> def typedFunction[T]: T => Boolean = funObj
typedFunction: [T]=> T => Boolean
scala> val f1 = typedFunction[String]
f1: String => Boolean = <function1>
scala> val f2 = typedFunction[Int]
f2: Int => Boolean = <function1>
scala> f1 eq f2
res0: Boolean = true
This works because trait Function1[-T1, +R] is contravariant of type T1.
In scala, Function values are parametrically monomorphic(while methods are polymorphic)
Shapeless library introduces polymorphic function values which may be mapped over HLists and many more other features.
Please consider the following refs:
http://www.chuusai.com/2012/04/27/shapeless-polymorphic-function-values-1/
http://www.chuusai.com/2012/05/10/shapeless-polymorphic-function-values-2/
Just wanted to know question w.r.t Currying
If we have defined the curried function curriedNewSum
scala> def curriedNewSum(x : Int)(y : Int) = x + y
curriedNewSum: (x: Int)(y: Int)Int
scala> curriedNewSum(10)(20)
res5: Int = 30
scala> var tenPlus = curriedNewSum(10)_
tenPlus: (Int) => Int = <function1>
scala> tenPlus(20)
res6: Int = 30
scala> var plusTen = curriedNewSum(_)(20)
<console>:6: error: missing parameter type for expanded function ((x$1) => curri
edNewSum(x$1)(20))
var plusTen = curriedNewSum(_)(20)
^
So why does curriedNewSum(10)_ works & curriedNewSum(_)(10) not?
I'm not 100% sure what exactly is the problem, but I strongly suspect this isn't doing what you think it is.
Try, for instance,
var plusTen = curriedNewSum(_)
You'll see it will return a Function1[Int, Function1[Int, Int]]. Now try this:
var plusTen = (curriedNewSum(_))(10)
And see it work! Well, that translates into:
var plusTen = ((x: Int) => curriedNewSum(x))(10)
While the other way translates into:
var plusTen = (x) => curriedNewSum(x)(10)
Something about how the function is expanding is screwing up with the type inference.
I am not exactly sure why it doesn't work. But this seems to work:
curriedNewSum(_:Int)(20)
After I thought about this more, it might be that the possibility exists of having an overloaded curriedNewSum methods
curriedNewSum(x:Double)(y:Int)
curriedNewSum(x:Float)(y:Int)
which one would be chosen? Defining the type explicitly says which method you want.
I suspect the type should be inferred where there is no ambiguity and that this is a bug or deliberately omitted.