Being relatively new at Scala, I was playing around with partially-applied function syntax on sbt console. I ran into a very weird issue in which I do not understand Scala's behavior.
The example is contrived and would unlikely be encountered in reality. That said, here it is. Suppose I define the following function:
scala> def f(x: Int, y: Int) = "%d %d".format(x, y)
Now if I type in
scala> f(1, _:Int)(2)
res: Int => Char = <function1>
The result is a Int => Char function, which is very unusual. In other words, Scala is (temporarily) treating f(1, _:Int) as a String (vs. its actual type: Int => String) when applying the parameter (i.e., 2).
If, instead, parentheses are used, what I expect to happen occurs:
scala> (f(1, _:Int))(2)
res: String = 1 2
However, this does not appear to be an order-of-operations issue, as I cannot find a way to add parentheses to achieve the unexpected behavior (i.e., having the result be of type Int => Char).
Any ideas?
At first about the result type of:
scala> f(1, _:Int)(2)
res: Int => Char = <function1>
Check this out:
scala> val str = "hello"
str: String = hello
scala> str(2)
res12: Char = l
I think this is clear.
No to the function itself, as it also easy. When you are lifting it to a function with an underscore you are lifting not only f, but also with a call (2) on a string (first result), which is why you get:
res: Int => Char = <function1>
Added
More explicit version. You function f is of type (Int, Int) => String, when you write f(1, _: Int), you are partially applying it to the argument one and returning a function of type Int => String, where Int is the second argument. Then your argument (2) call apply method on the result string from the function Int => String which returns you a Char, from here you get function of type Int => Char, where Int is a second argument to your f function and Char is a char from the resulting string
In the second case, where you have:
scala> (f(1, _:Int))(2)
res: String = 1 2
by parenthesis you are spliting this into to things, the first one is a function Int => String and (2) calls this function, you are passing an argument 2 into this function Int => String:
val ff = f(1, _: Int)
val res = ff(2)
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).
I have the following two methods in Scala:
def myFunc: Int => String = { age =>
"Here " + age
}
def myFunc2 (age: Int) : String = {
"Here" + age
}
Is there any difference in these two methods? (other than the names of course). The syntax looks quite different to me. Is it just a matter of style? Is one prefered over the other?
Yes, there is a difference. The former is a method which takes no arguments and returns a function of type Function1[Int, String]. The latter is a method taking a String and returning an Int.
In Scala, methods with arity-0 can be declared and invoked without parenthesis, so invoking myFunction(1) and myFunction2(1) looks the same.
If we'd convert both methods to functions, you'd see the difference in the fact that the former would take the shape of Function0[Function1[Int, String]], while the latter would be Function1[Int, String]:
myFunc: Int => String
myFunc2: (age: Int)String
scala> myFunc _
res6: () => Int => String = <function0>
scala> myFunc2 _
res7: Int => String = <function1>
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).
If I define a simple stringToInt function and store it as a val, everything works as expected, e.g.
scala> def stringToInt1: (String => Int) = _.toInt
stringToInt1: String => Int
scala> stringToInt1("1")
res0: Int = 1
However, if I then make that implicit, it causes a stack overflow:
scala> implicit def stringToInt2: (String => Int) = _.toInt
stringToInt2: String => Int
scala> stringToInt2("1")
java.lang.StackOverflowError
at .stringToInt2(<console>:7)
at $anonfun$stringToInt2$1.apply(<console>:7)
at $anonfun$stringToInt2$1.apply(<console>:7)
...
At first I suspected that this was because the underscore wasn't resolving to what I expected, but that's not the case, as this style of implicit val works fine for the following simple function:
scala> implicit def plusTwo: (Int => Int) = _ + 2
plusTwo: Int => Int
scala> plusTwo(2)
res2: Int = 4
If I define the parameter explicitly, no stack overflow:
scala> implicit def stringToInt3(s: String) = s.toInt
stringToInt3: (s: String)Int
scala> stringToInt3("1")
res3: Int = 1
(If trying this yourself and this last case stack overflows, restart the scala console and redo this last step)
So my question is, why is the original implicit not correctly resolving?
Edit
Ok digging a little deeper here, it seems that the problem is with the implicit conversion from String to StringOps. If we cut that out, it works fine:
scala> import scala.collection.immutable.StringOps
import scala.collection.immutable.StringOps
scala> implicit def stringToInt4: (String => Int) = new StringOps(_).toInt
stringToInt4: String => Int
scala> stringToInt4("1")
res4: Int = 1
But why would that implicit conversion be causing the issue?
Adding to the other replies.
There is no toInt method on String. Scala has to find an implicit conversion that will yield a type that has a toInt method.
Usually the StringOps conversion provides this toInt.
However Int has a toInt too, so scala finds your conversion from String => Int and decides that it has precedence over the StringOps conversion, thus applying it recursively.
This is why StringToInt4 works, as you explicitly tell the compiler what conversion you want. Maybe you could write it as: implicit def stringToInt5: (StringOps => Int) = _.toInt or check how implicits are resolved and how one takes precedence over the other.
Note what you are doing here:
scala> def stringToInt1: (String => Int) = _.toInt
stringToInt1: String => Int
You are defining a method (using def) that takes no parameters and returns a function from String to Int. Are you doing it this way on purpose, or is it just because you don't exactly understand the syntax?
You could have created a val instead:
val stringToInt1: (String => Int) = _.toInt
Now, stringToInt1 is a val that contains a function to convert String to Int.
With your stringToInt2, Scala is recursively applying the method. I don't know why it does that in the case of stringToInt2 but not with plusTwo.
Note that stringToInt3 is not the same thing as stringToInt1 and stringToInt2. It's a method that takes a String and returns an Int, not a method that takes no parameters and returns a function from String to Int.
def foo(x: Int, f: Unit => Int) = println(f())
foo(2, { Unit => 3 + 4 })
// case 1
def loop: Int = 7
foo(2, loop) // does not compile
changing loop to
// case 2
def loop(): Int = 7
foo(2, loop) // does not compile
changing loop to
// case 3
def loop(x: Unit): Int = 7 // changing according to Don's Comments
foo(2, loop) // compiles and works fine
Shouldn't case 1 and case 2 also work? Why are they not working?
Defining foo as
def foo(x: Int, y: () => Int)
then case 2 works but not case 1.
Arent they all supposed to work, defining the functions either way?
Also I think () => Int in foo is a bad style, y:=> Int does not work. Comments?
Scala distinguishes between the following things:
Functions/methods with no parameter lists ("by-name parameter" if a function)
Functions with one empty parameter list
Functions with one parameter of type Unit
None of these are equivalent, although as a convenience Scala allows you to elide empty parameter lists. (Incidentally, two empty parameter lists are also not the same.)
So, even though Unit is written (), this is not the same as the function argument parens () for a function or method. Instead, think of () as a Tuple0.
So, if you say f: Unit => Int, what you mean is "f takes one parameter, but it's a really boring parameter because it is Unit, which must always be the same boring Tuple0 value ()". What you're writing is really short for f: (Unit) => Int.
If you say f: () => Int, then you mean that "f takes no parameters and produces an Int".
If you say f: => Int, then you mean that "delay the execution of whatever statement produces an Int value until we use it in this code (and re-evaluate it each time)". Functionally, this ends up being basically the same as f: () => Int (and internally is converted into the same Function0 class), but it has a different usage, presumably to allow for a more compact form of closures (you always omit the => in the calling code).
()=>Int is Function0[Int] while Unit=>Int is Function1[Unit,Int]
scala> val function0: () => Int = () => 5
function0: () => Int = <function0>
scala> val function1: Unit => Int = u => 5
function1: (Unit) => Int = <function1>
scala> function0()
res0: Int = 5
scala> function1("anything")
res1: Int = 5
scala> function1(100)
res2: Int = 5
scala>
Also note that () is an object of Unit
scala> function1(())
res11: Int = 5
scala> function1 ()
res12: Int = 5
scala> function1()
res13: Int = 5
scala> val unit = ()
unit: Unit = ()
scala> function1(unit)
res15: Int = 5
scala> function1 apply unit
res16: Int = 5
scala>
In case 1 and 2 above, the return value of loop rather than loop itself is type checked for the second argument to foo and fails: Int != Unit => Int
The change to loop has a typo.