I am trying to understand how to perform an operation when using foreach
. For e.g. how can I print element+1 of alist
using foreach
My Scala is exceedingly rusty, and I don't have a medium to test the code on, so please notify me of any syntax issues.
Scala has issues automatically inferring the type of parameters of anonymous functions in some circumstances. From my experience, it's best to just say the types explicitly, else risk recieving the wrath of the compiler. If all you're trying to do is add one to each element and print the result, try:
alist.foreach(
n: Int => println(n + 1)
)
Note the purpose of foreach
though. It is intended to be used when you want to carry out side effects over a list. If your intent was to create a second list where each element is + 1 the original list, use a generator/map function instead.
And regarding your second example, if you think on it, it will be clear why it doesn't work. println
returns void/Unit, which you then try to access the toInt
method of.
Edit:
As noted in the comments, in this case, type annotations aren't required. I still prefer to place them though. I prefer explicit types unless they're bloating the code (personal choice).
Using the Placeholder Syntax for Anonymous Functions in Scala is a bit tricky. The language specification says:
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.
The bold text establishes how the Scala compiler determines which expression is the anonymous functions created with the placeholder operator - it is always the innermost expression, which properly contains the _
operator. In the case of alist.foreach(println(_+1))
, the expression that binds the underscore is _ + 1
. It is not bound by the entire println(_ + 1)
expression since _ + 1
is properly contained in println(_ + 1)
. As already written in the other answers, in that case you must use the explicit syntax for anonymous functions:
alist.foreach(x => println(x + 1))
For the sake of completeness: alist.foreach(println(_+1))
translates to alist.foreach(println(x => x + 1))
. Since println
takes arguments of various kinds, the compiler is not able to infer uniquely a type for x
and hence the missing parameter type error in that case. Even if you were to give x
a type, another error will ensue since foreach
expects a function that takes one argument of the elemental type of alist
.
The issue here is that Scala thinks you're trying to pass a function "(something)+1" to the println method rather than passing it to the foreach method.
Doing just "println(_)" works because in this case you're not passing a function to println. Instead you're defining a partial application of println. The partial application is a function and can be passed to foreach.
This will work for you:
alist.map(_+1).foreach(println)
For e.g. how can I add +1 to each element of a list using foreach
To answer your updated question, you can definitely use foreach
:
alist.foreach(x => println(x + 1))
You can't use placeholder syntax inside println
since the compler infers it as:
alist.foreach(x => println(x => x + 1))
According to it's expansion laws. println
takes a parameter of type Any
, so it can't bind it to a concrete type with a plus method.
If you're interested in the rules of placeholder syntax, see Hidden features of Scala
You cannot mutate a List[+A]
using foreach
in Scala, since lists are immutable and foreach
return type is Unit
. What you can do is project a new list from an existing one using the map
transformation:
scala> val list = List(1,2,3,4)
list: List[Int] = List(1, 2, 3, 4)
scala> val plusOneList = list.map(_ + 1)
plusOneList: List[Int] = List(2, 3, 4, 5)
If you look at the signature for foreach
, you see that it takes a function: A => Unit
, which takes an element of type A and projects back a Unit. This signature is a sign for a side effecting method and since list is immutable, that doesn't help us.
If you used a mutable list, such as ListBuffer
, then you could use side effects for population:
scala> val listBuffer = mutable.ListBuffer[Int]()
listBuffer: scala.collection.mutable.ListBuffer[Int] = ListBuffer()
scala> (0 to 4).foreach(x => listBuffer += x)
scala> listBuffer
res10: scala.collection.mutable.ListBuffer[Int] = ListBuffer(0, 1, 2, 3, 4)