Suppose l = List(1, 2, 3):
scala> l foreach { println _ }
1
2
3
scala> l foreach { println }
1
2
3
l foreach { println _ } <=> l foreach { println } because _ can be omitted. But why does the following also produces the same result?
scala> l foreach { println(_) }
1
2
3
Shouldn't the _ be bounded to println instead of foreach?
in other words:
l foreach { println(_) } <=> l foreach { println(x => x) }
and therefore throws an error on missing parameter type?
l foreach { println(_.toString) } produces the expected missing parameter type error
foreach takes a function A => Unit, in this case, Int => Unit
println satisfies this condition, but it is a method, not a function. Scala can get around this though, through a technique called eta expansion. It creates a function that takes the inputs for the method and called the method with those inputs. In your case, it looks similar to (x: Int) => println(x).
Each way you've written accomplishes this.
l foreach { println }
Here Scala is able to infer that you want to treat println as a function and pass it to foreach
l foreach { println _ }
By adding the underscore you explicitly saying that you want to turn the method into a function
l foreach { println(_) }
This is similar to the last, for any method you call, you can use an underscore instead of passing a parameter. By doing this, instead of calling the method you create a partially-applied function. You then pass this function to foreach
l foreach { println(_.toString) }
This is quite a bit different. _.toString creates a function A => String but Scala cannot figure out the correct type for A. Another problem is not you are passing a value to println, so you are calling println and passing the result to foreach instead of turning it into a function. println returns Unit which is the wrong type to pass to foreach
Shouldn't the _ be bounded to println instead of foreach? in other words:
l foreach { println(_) } <=> l foreach { println(x => x) }
No, this is specifically excluded by rules for placeholders in anonymous functions:
An expression e of syntactic category Expr binds an underscore section u, if the following two conditions hold: (1) e properly contains u, and (2) there is no other expression of syntactic category Expr which is properly contained in e and which itself properly contains u.
"Properly contains" means _ never binds itself, and so it never expands to x => x. In your last example, _.toString does properly contain _ and so satisfies both conditions above.
You're forgetting that println(x) can also be written as println x in Scala. If there's only a single argument, the parenthesis are optional.
Related
This Scala code compiles under Scala 2.13
val res = new scala.collection.mutable.StringBuilder
"hello".foreach { c =>
if (true) {
(0 until 10).foreach( res += c )
}
}
If you see the foreach method is missing argument for anonymous function. When it is executed it gives an exception StringIndexOutOfBoundsException for res += c which is puzzling since StringBuilder should always be appendable.
Following code runs fine and there are no exceptions. The only change is adding _ as placeholder for foreach parameter function:
val res = new scala.collection.mutable.StringBuilder()
"hello".foreach { c =>
if (true) {
(0 until 10).foreach( _ => res += c )
}
}
The answer to your question lies in String.apply() or StringBuilder.apply() to be more exact.
You see, foreach expects a function. In more exact words, an expression which evaluates to a function.
So, it will first evaluate the expression to get the function then it will apply that function for 0 until 10
so when you consider the first iteration of outer foreach, you have c = 'h' and following,
(0 until 10).foreach(res += c )
Here, res += c will return res after appending h to it.
So... the evaluated function is res or res.apply with res = "h". Hence, the above is actually,
(0 until 10).foreach("h".apply)
So, res.apply(0) goes well... but res.apply(1) fails with StringIndexOutOfBoundsException.
Please see the signature for
def foreach[U](f: A => U): Unit = {
}
(f: A => U) this is a function, not an expression.
I want to execute a function three times. That function happens to return a string.
def doThingReturnString(): String = {
println("Did a thing, returned a string.")
"abcdef"
}
(1 to 3).foreach { n =>
doThingReturnString()
}
(1 to 3).foreach {
doThingReturnString()
}
I expect both loops to print three lines. Instead, the first loop prints three lines and the second loop prints one.
Did a thing, returned a string.
Did a thing, returned a string.
Did a thing, returned a string.
Did a thing, returned a string.
Why does naming the parameter cause the loop to only execute once?
foreach expects a function Int => U (where U can be "whatever"). Period. If you want to ignore the parameter, use an underscore.
(1 to 3).foreach { _ => doThingReturnString() }
When you write
(1 to 3).foreach { doThingReturnString() }
The braces act like parentheses
(1 to 3).foreach(doThingReturnString())
The argument for foreach must be Int => U, but here, it is a String. A String can be implicitly converted to an Int => U, because a String can implicitly convert to WrappedString, which treats it as a collection type, specifically as a Seq[Char], which can be upcast to a PartialFunction[Int, Char] from indices to elements, which can be upcast to Int => Char. Thus, you've essentially written
val temp = doThingReturnString()
(1 to 3).foreach { i => temp.charAt(i) }
The reason for this behavior is that treating Seq[A]s as PartialFunction[Int, A]s is pretty sensible. Also sensible is being able to treat strings like the other collection types, so we have an implicit conversion to augment Java's String with Scala's collection architecture. Putting them together, so that Strings turn into Int => Chars, produces somewhat surprising behavior.
Let's change your expression to:
(1 to 3).foreach { "abc"}
Can you guess the result? It is
java.lang.StringIndexOutOfBoundsException: String index out of range: 3
If we change it to
(1 to 3).foreach { "abcd"}
the program executes without the exception. So, in case of your expression:
(1 to 3).foreach {
doThingReturnString()
}
you: firstly execute doThingReturnString(), which returns a string "abcdef". Then, for each number i in the range 1 to 3, the compiler executes "abcdef"(i).
As to why (1 to 3).foreach { n => doThingReturnString() } is seemingly treated differently from (1 to 3).foreach { doThingReturnString() }, the best explanation I know comes from the book Scala Puzzlers (p. 20; no affiliation with the authors):
Since anonymous functions are often passed as arguments, it’s common
to see them surrounded by { ... } in code. It’s easy to think that
these curly braces represent an anonymous function, but instead they
delimit a block expression: one or multiple statements, with the last
determining the result of the block.
Consider this:
object Intercept { def apply[T](v: T) { println(s"Intercept called with value '$v'") } }
(1 to 3).foreach { Intercept[Int] } // or just (1 to 3) foreach Intercept[Int]
, that outputs:
Intercept called with value '1'
Intercept called with value '2'
Intercept called with value '3'
And consider this
(1 to 3).foreach { println("start"); println }
that prints
start
1
2
3
vs
(1 to 3).foreach { x => println("start"); println(x) }
that prints
start
1
start
2
start
3
So,
if anonymous function is provided (elem =>), everything gets executed
if block is provided, then foreach acts on the result of the block (the last line) invoking 'apply(_)' on it, with the exception where _ is used.
def fun(f: Int => Unit) {
f(10)
f(20)
}
println("method 1 call:")
fun(i => {println("hi"); println(i)})
println("method 2 call:")
fun{println("hi"); println(_)}
The output is:
E:\test\scala>scala i.scala
method 1 call:
hi
10
hi
20
method 2 call:
hi
10
20
I think i => {println("hi"); println(i)} and println("hi"); println(_) are the same. Because we have one parameter and the parameter is used just once, we can use _ to simplify the code.
Then, why does method 2 just print "hi" once?
(Does it mean: if I want to use _ to simple the calling, the contents on the right of => just can have one expression, if have more than one, e.g. println("hi"); println(i); Then, we can not use _ to replace?
println(_) expands to x => println(x), so {println("hi"); println(_)} expands to {println("hi"); x => println(x)}. So when fun{println("hi"); println(_)} executes, the following steps take place:
The expression {{println("hi"); println(_)}} is evaluated. Which means:
println("hi") is evaluated and then
x => println(x) is evaluated, creating a function object that will print its argument.
The thus-created function object is the result of the expression.
The method func is called with the created function object as its argument. func will call the function with 10 and 20, causing it to print those numbers.
First, you have to know that in scala { block; of; code } is an expression that evaluates to whatever the last expression inside it evaluates to.
When you say:
fun(i => { println("hi"); println(i) })
you create an anonymous function, which body contains 2 expressions, both returning () and both are evaluated when function is called, everything as expected.
But when you say
fun({println("hi"); println(_)})
You pass in a block, not an anonymous function. As sepp2k explained this expands to
{ println("hi"); x => println(x) }
So, you pass a block to fun, this block is being evaluated before it is passed. So first println("hi") happens, it is printed just once as block is evaluated once, and then this x => println(x) is evaluated, which is a function Int => Unit, that prints its argument. This, and only this (as a last expression is passed to the fun. This is why each time you call fun it just prints the argument twice.
To see further on how block could work you can look at this example that does more in the block
fun {
println("building the function")
val uuidOfThisFunction = UUID.randomUUID
x => println(s"$uuidOfThisFunction, $x")
}
So this block prepares a function giving it some extra context through the closure. This uuid will stay the same for both calls that happen if fun.
building the function
86e74b5e-83b5-41f3-a71c-eeafcd1db2a0, 10
86e74b5e-83b5-41f3-a71c-eeafcd1db2a0, 20
The example that would look more like what you did with first call would be
fun(
x => {
println("calling the function")
val uuidOfThisCall = UUID.randomUUID
println(s"$uuidOfThisCall, $x")
}
)
The block evaluates every time f is called.
calling the function
d3c9ff0a-84b4-47a3-8153-c002fa16d6c2, 10
calling the function
a0b1aa5b-c0ea-4047-858b-9db3d43d4983, 20
While answering this question I stumbled upon a behavior I could not explain.
Coming from:
val builder = new StringBuilder("foo bar baz ")
(0 until 4) foreach { builder.append("!") }
builder.toString -> res1: String = foo bar baz !
The issue seemed clear, the function provided to the foreach was missing the Int argument, so StringBuilder.apply got executed. But that does not really explain why it appends the '!' only once. So I got to experimenting..
I would have expected the following six statements to be equivalent, but the resulting Strings differ:
(0 until 4) foreach { builder.append("!") } -> res1: String = foo bar baz !
(0 until 4) foreach { builder.append("!")(_) } -> res1: String = foo bar baz !!!!
(0 until 4) foreach { i => builder.append("!")(i) } -> res1: String = foo bar baz !!!!
(0 until 4) foreach { builder.append("!").apply } -> res1: String = foo bar baz !
(0 until 4) foreach { builder.append("!").apply(_) } -> res1: String = foo bar baz !!!!
(0 until 4) foreach { i => builder.append("!").apply(i) } -> res1: String = foo bar baz !!!!
So the statements are obviously not equivalent. Can somebody explain the difference?
Let's label them:
A - (0 until 4) foreach { builder.append("!").apply }
B - (0 until 4) foreach { builder.append("!").apply(_) }
C - (0 until 4) foreach { i => builder.append("!").apply(i) }
At first glance it is confusing, because it appears they should all be equivalent to each other. Let's look at C first. If we look at it as a Function1, it should be clear enough that builder.append("!") is evaluated with each invocation.
val C = new Function1[Int, StringBuilder] {
def apply(i: Int): StringBuilder = builder.append("!").apply(i)
}
For each element in (0 to 4), C is called, which re-evaluates builder.append("!") on each invocation.
The important step to understanding this is that B is syntactic sugar for C, and not A. Using the underscore in apply(_) tells the compiler to create a new anonymous function i => builder.append("!").apply(i). We might not necessarily expect this because builder.append("!").apply can be a function in it's own right, if eta-expanded. The compiler appears to prefer creating a new anonymous function, that simply wraps builder.append("!").apply, rather than eta-expanding it.
From the SLS 6.23.1 - Placeholder Syntax for Anonymous Functions
An expression e of syntactic category Expr binds an underscore section u, if the following two conditions hold: (1) e properly contains u, and (2) there is no other expression of syntactic category Expr which is properly contained in e and which itself properly contains u.
So builder.append("!").apply(_) properly contains the underscore, so the underscore syntax can applies for the anonymous function, and it becomes i => builder.append("!").apply(i), like C.
Compare this to:
(0 until 4) foreach { builder.append("!").apply _ }
Here, the underscore is not properly contained in the expression, so the underscore syntax does not immediately apply as builder.append("!").apply _ can also mean eta-expansion. In this case, eta-expansion comes first, which will be equivalent to A.
For A, it is builder.append("!").apply is implicitly eta-expanded to a function, which will only evaluate builder.append("!") once. e.g. it is something like:
val A = new Function1[Int, Char] {
private val a = builder.append("!")
// append is not called on subsequent apply calls
def apply(i: Int): Char = a.apply(i)
}
scala.collection.mutable.StringBuilder extends (Int => Char), and therefore builder.append("!"), which returns a StringBuilder, is a valid function argument to foreach. The first line is therefore equivalent as if you wrote:
val f: Int => Char = builder.append("!").asInstanceOf[Int => Char] // appends "!" once
(0 until 4).foreach(f) // fetches the 0th to 3rd chars in the string builder, and does nothing with them
All the lines that append !!!! actually create a new anonymous function i => builder.append("!").apply(i), and are therefore equivalent to
val f: Int => Char = (i: Int) => builder.append("!").apply(i)
(0 until 4).foreach(f) // appends 4 times (and fetches the 0th to 3rd chars in the string builder, and does nothing with them)
As for your fourth line, it's weirder IMO. In that case, you are trying to read a "field" apply in builder.append("!"). But apply is a method (Int)Char, and the expected type (as determined by the param type of foreach) is Int => ?. So there is a way to lift the method apply(Int)Char as an Int => ?, which is to create a lambda that will call the method. But in this case, since you're trying to read apply as field, initially, it means that the this of .apply should be evaluated once to be stored as a capture for the this parameter of the method call, giving something equivalent to this:
val this$1: StringBuilder = builder.append("!") // appends "!" once
val f: Int => Char = (i: Int) => this$1.apply(i)
(0 until 4).foreach(f) // fetches the 0th to 3rd chars in the string builder, and does nothing with them
I have a map m
val m = Map(1->2, 3->4, 5->6, 7->8, 4->4, 9->9, 10->12, 11->11)
Now i want a map whose keys are equal to the values. So i do this
def eq(k: Int, v: Int) = if (k == v) Some(k->v) else None
m.flatMap((k,v) => eq(k,v))
This gives me the error
error: wrong number of parameters; expected = 1
m.flatMap((k,v) => eq(k,v))
Whats wrong with the above code? flatMap expects a one argument function and here i am passing one argument which is a Pair of integers.
Also this works
m.flatMap {
case (k,v) => eq(k,v)
}
but this does not
m.flatMap {
(k,v) => eq(k,v)
}
Looks like i am missing something. Help?
There is no such syntax:
m.flatMap((k,v) => eq(k,v))
Well, in fact there is such syntax, but actually it is used in functions that accept two arguments (like reduce):
List(1,2,3,4).reduce((acc, x) => acc + x)
The
m.flatMap {
case (k,v) => eq(k,v)
}
syntax works because in fact it is something like this:
val temp: PartialFunction[Tuple2[X,Y], Tuple2[Y,X]] = {
case (k,v) => eq(k,v) // using literal expression to construct function
}
m.flatMap(temp) // with braces ommited
They key thing here is the usage of case word (actually, there is a discussion to enable your very syntax) which turns usual braces expression, like { ... } into full blown anonymous partial function
(If you want to simply fix the error you're getting, see the 2nd solution (with flatMap); if you want a generally nicer solution, read from the beginning.)
What you need instead is filter not flatMap:
def eq(k: Int, v: Int) = k == v
val m = Map(1->2, 3->4, 5->6, 7->8, 4->4, 9->9, 10->12, 11->11)
m.filter((eq _).tupled)
...which of course reduces to just the following, without the need for eq:
m.filter { case (k, v) => k == v }
result:
Map(9 -> 9, 11 -> 11, 4 -> 4)
OR... If you want to stick with flatMap
First you must know that flatMap will pass to your function TUPLES not keys and values as separate arguments.
Additionally, you must change the Option returned by eq to something that can be fed back to flatMap on sequences such as List or Map (actually any GenTraversableOnce to be precise):
def eq(k: Int, v: Int) = if (k == v) List(k -> v) else Nil
m.flatMap { case (k,v) => eq(k,v) } // use pattern matching to unpack the tuple
or the uglier but equivalent:
m.flatMap { x => eq(x._1, x._2) }
alternatively, you can convert eq to take a tuple instead:
m.flatMap((eq _).tupled)
I think that what you want is a single argument that will be a couple, not two arguments. Something like this may work
m.flatMap(k => eq(k._1, k._2))
The code snippet that works uses pattern matching. You give names to both elements of your couple. It's a partial function and can be use here in your flatMap.
You have to do:
m.flatMap { case (k,v) => eq(k,v) }
Note that here I switch to curly braces, which indicates a function block rather than parameters, and the function here is a case statement. This means that the function block I'm passing to flatMap is a partialFunction that is only invoked for items that match the case statement.
Your eq function takes two parameters, that is why you are getting the type error. Try:
def f(p: (Int, Int)) = if (p._1 == p._2) Some(p) else None
m flatMap f